Skip to main content

zulip_api/
message.rs

1//! Message types for the Zulip API.
2
3use serde::{Deserialize, Serialize};
4
5use crate::{field_access, impl_cow, impl_default, impl_display};
6
7mod attachment;
8mod basic_channel;
9mod bot;
10mod bot_service;
11mod bot_type;
12mod channel_folder;
13mod channel_permission;
14mod client_capabilities;
15mod content_type;
16mod cross_realm_bot;
17mod custom_profile;
18mod default_channel_group;
19mod display_recipient;
20mod draft;
21mod edit_history;
22mod event_type;
23mod flag;
24mod giphy_rating_option;
25mod group_permission_setting;
26mod group_setting;
27mod include_subscribers;
28mod msg_type;
29mod muted_topic;
30mod muted_user;
31mod navigation_view;
32mod never_subscribed;
33mod onboarding_step;
34mod operation;
35mod presence;
36mod profile_data;
37mod propagate_mode;
38mod push_device;
39mod reaction;
40mod realm_authentication_method;
41mod realm_available_video_chat_provider;
42mod realm_billing;
43mod realm_create_private_stream_policy;
44mod realm_create_public_stream_policy;
45mod realm_create_web_public_stream_policy;
46mod realm_default_external_account;
47mod realm_domain;
48mod realm_embedded_bot;
49mod realm_emoji;
50mod realm_filter;
51mod realm_incoming_webhook_bot;
52mod realm_linkifier;
53mod realm_message_edit_history_visibility_policy;
54mod realm_organization_type;
55mod realm_plan_type;
56mod realm_playground;
57mod realm_user_settings_default;
58mod realm_video_chat_provider;
59mod realm_wildcard_mention_policy;
60mod recent_private_conversation;
61mod report_type;
62mod role;
63mod saved_snippet;
64mod scheduled_message;
65mod server_supported_permission_setting;
66mod server_thumbnail_format;
67mod submessage;
68mod subscription;
69mod to;
70mod topic_link;
71mod topics_policy;
72mod unread_msgs;
73mod user;
74mod user_group;
75mod user_settings;
76mod user_status;
77mod user_topic;
78mod webhook_config;
79
80pub mod delete_message;
81pub mod edit_message;
82pub mod emoji_reaction;
83pub mod fetch_api_key;
84pub mod get_file_temporary_url;
85pub mod get_message;
86pub mod get_message_history;
87pub mod get_messages;
88pub mod get_read_receipts;
89pub mod mark_all_as_read;
90pub mod mark_stream_as_read;
91pub mod mark_topic_as_read;
92pub mod matches_narrow;
93pub mod register;
94pub mod render;
95pub mod report_message;
96pub mod response;
97pub mod send_message;
98pub mod update_message_flags;
99pub mod update_message_flags_narrow;
100pub mod upload_file;
101
102pub use attachment::{Attachment, AttachmentMessage};
103pub use basic_channel::BasicChannel;
104pub use bot::Bot;
105pub use bot_service::{
106    BotService, BotServiceEmbedded, BotServiceOutgoingWebhook, OutgoingWebhookInterface,
107};
108pub use bot_type::BotType;
109pub use channel_folder::ChannelFolder;
110pub use channel_permission::{
111    CanAddSubscribersGroup, CanAdministerChannelGroup, CanDeleteAnyMessageGroup,
112    CanDeleteOwnMessageGroup, CanMoveMessagesOutOfChannelGroup, CanMoveMessagesWithinChannelGroup,
113    CanRemoveSubscribersGroup, CanResolveTopicsGroup, CanSendMessageGroup, CanSubscribeGroup,
114};
115pub use client_capabilities::ClientCapabilities;
116pub use content_type::ContentType;
117pub use cross_realm_bot::CrossRealmBot;
118pub use custom_profile::{CustomProfileField, CustomProfileFieldType};
119pub use default_channel_group::DefaultChannelGroup;
120pub use display_recipient::{DisplayRecipient, UserRecipient};
121pub use draft::{Draft, DraftType};
122pub use edit_history::EditHistory;
123pub use event_type::EventType;
124pub use flag::Flag;
125pub use giphy_rating_option::GiphyRatingOption;
126pub use group_permission_setting::GroupPermissionSetting;
127pub use group_setting::{GroupSetting, GroupSettingIds};
128pub use include_subscribers::IncludeSubscribers;
129pub use msg_type::MessageType;
130pub use muted_topic::MutedTopic;
131pub use muted_user::MutedUser;
132pub use navigation_view::NavigationView;
133pub use never_subscribed::NeverSubscribed;
134pub use onboarding_step::{OnboardingStep, OnboardingType};
135pub use operation::Operation;
136pub use presence::{
137    LegacyPresenceFormat, LegacyPresenceStatus, ModernPresenceFormat, Presence, PresenceList,
138};
139pub use profile_data::ProfileData;
140pub use propagate_mode::PropagateMode;
141pub use push_device::{PushDevice, PushDeviceStatus};
142pub use reaction::{Reaction, ReactionType};
143pub use realm_authentication_method::RealmAuthenticationMethod;
144pub use realm_available_video_chat_provider::RealmAvailableVideoChatProvider;
145pub use realm_billing::RealmBilling;
146pub use realm_create_private_stream_policy::RealmCreatePrivateStreamPolicy;
147pub use realm_create_public_stream_policy::RealmCreatePublicStreamPolicy;
148pub use realm_create_web_public_stream_policy::RealmCreateWebPublicStreamPolicy;
149pub use realm_default_external_account::RealmDefaultExternalAccount;
150pub use realm_domain::RealmDomain;
151pub use realm_embedded_bot::RealmEmbeddedBot;
152pub use realm_emoji::RealmEmoji;
153pub use realm_filter::RealmFilter;
154pub use realm_incoming_webhook_bot::RealmIncomingWebhookBot;
155pub use realm_linkifier::RealmLinkifier;
156pub use realm_message_edit_history_visibility_policy::RealmMessageEditHistoryVisibilityPolicy;
157pub use realm_organization_type::RealmOrganizationType;
158pub use realm_plan_type::RealmPlanType;
159pub use realm_playground::RealmPlayground;
160pub use realm_user_settings_default::*;
161pub use realm_video_chat_provider::RealmVideoChatProvider;
162pub use realm_wildcard_mention_policy::RealmWildcardMentionPolicy;
163pub use recent_private_conversation::RecentPrivateConversation;
164pub use report_type::ReportType;
165pub use role::Role;
166pub use saved_snippet::SavedSnippet;
167pub use scheduled_message::{ScheduledMessage, ScheduledMessageTo, ScheduledMessageType};
168pub use server_supported_permission_setting::ServerSupportedPermissionSetting;
169pub use server_thumbnail_format::ServerThumbnailFormat;
170pub use submessage::Submessage;
171pub use subscription::*;
172pub use to::MessageTo;
173pub use topic_link::TopicLink;
174pub use topics_policy::TopicsPolicy;
175pub use unread_msgs::{UnreadMsgs, UnreadMsgsHuddle, UnreadMsgsPm, UnreadMsgsStream};
176pub use user::User;
177pub use user_group::UserGroup;
178pub use user_settings::{UserSettings, UserSettingsEmojisetChoice};
179pub use user_status::UserStatus;
180pub use user_topic::UserTopic;
181pub use webhook_config::{WebhookConfigOption, WebhookUrlOption};
182
183/// Represents a message returned by the Zulip API server.
184#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
185pub struct Message {
186    #[serde(skip_serializing_if = "Option::is_none")]
187    avatar_url: Option<String>,
188    client: String,
189    content: String,
190    content_type: ContentType,
191    display_recipient: DisplayRecipient,
192    edit_history: Option<Vec<EditHistory>>,
193    id: u64,
194    is_me_message: bool,
195    last_edit_timestamp: Option<u64>,
196    last_moved_timestamp: Option<u64>,
197    reactions: Vec<Reaction>,
198    recipient_id: u64,
199    sender_email: String,
200    sender_full_name: String,
201    sender_id: u64,
202    sender_realm_str: String,
203    #[serde(skip_serializing_if = "Option::is_none")]
204    stream_id: Option<u64>,
205    subject: String,
206    submessages: Vec<Submessage>,
207    timestamp: u64,
208    #[serde(rename = "type")]
209    msg_type: MessageType,
210    flags: Vec<Flag>,
211    #[serde(skip_serializing_if = "Option::is_none")]
212    match_content: Option<String>,
213    #[serde(skip_serializing_if = "Option::is_none")]
214    match_subject: Option<String>,
215}
216
217impl Message {
218    /// Creates a new [Message].
219    pub const fn new() -> Self {
220        Self {
221            avatar_url: None,
222            client: String::new(),
223            content: String::new(),
224            content_type: ContentType::new(),
225            display_recipient: DisplayRecipient::new(),
226            edit_history: None,
227            id: 0,
228            is_me_message: false,
229            last_edit_timestamp: None,
230            last_moved_timestamp: None,
231            reactions: Vec::new(),
232            recipient_id: 0,
233            sender_email: String::new(),
234            sender_full_name: String::new(),
235            sender_id: 0,
236            sender_realm_str: String::new(),
237            stream_id: None,
238            subject: String::new(),
239            submessages: Vec::new(),
240            timestamp: 0,
241            msg_type: MessageType::new(),
242            flags: Vec::new(),
243            match_content: None,
244            match_subject: None,
245        }
246    }
247}
248
249field_access! {
250    Message {
251        avatar_url: option_cow_deref { str, String },
252        match_content: option_cow_deref { str, String },
253        match_subject: option_cow_deref { str, String },
254        edit_history: option_cow_deref { [EditHistory], Vec<EditHistory> },
255    }
256}
257
258field_access! {
259    Message {
260        client: cow { str },
261        content: cow { str },
262        display_recipient: cow { DisplayRecipient },
263    }
264}
265
266field_access! {
267    Message {
268        content_type: ContentType,
269        id: u64,
270        is_me_message: bool,
271        recipient_id: u64,
272        sender_id: u64,
273        timestamp: u64,
274        msg_type: MessageType,
275    }
276}
277
278field_access! {
279    Message {
280        last_edit_timestamp: option { u64 },
281        last_moved_timestamp: option { u64 },
282        stream_id: option { u64 },
283    }
284}
285
286field_access! {
287    Message {
288        reactions: cow { [Reaction] },
289        sender_email: cow { str },
290        sender_full_name: cow { str },
291        sender_realm_str: cow { str },
292        subject: cow { str },
293        submessages: cow { [Submessage] },
294        flags: cow { [Flag] },
295    }
296}
297
298impl_cow!(Message);
299impl_default!(Message);
300impl_display!(Message);
301
302#[cfg(test)]
303mod tests {
304    use super::*;
305
306    #[test]
307    fn test_message_minimal() {
308        let client = "client";
309        let content = "content";
310        let content_type = ContentType::Markdown;
311        let display_recipient = DisplayRecipient::Channel("recipient channel".into());
312        let id = 1;
313        let is_me_message = false;
314        let recipient_id = 4;
315        let sender_email = "sender@example.com";
316        let sender_full_name = "sender full name";
317        let sender_id = 5;
318        let sender_realm_str = "sender realm";
319        let subject = "test subject";
320        let timestamp = 7;
321        let msg_type = MessageType::Channel;
322
323        let message = Message::new()
324            .with_client(client)
325            .with_content(content)
326            .with_content_type(content_type)
327            .with_display_recipient(&display_recipient)
328            .with_id(id)
329            .with_is_me_message(is_me_message)
330            .with_recipient_id(recipient_id)
331            .with_sender_email(sender_email)
332            .with_sender_full_name(sender_full_name)
333            .with_sender_id(sender_id)
334            .with_sender_realm_str(sender_realm_str)
335            .with_subject(subject)
336            .with_timestamp(timestamp)
337            .with_msg_type(msg_type);
338
339        let message_json = message.to_string();
340
341        assert_eq!(message.client(), client);
342        assert_eq!(message.content(), content);
343        assert_eq!(message.content_type(), content_type);
344        assert_eq!(message.display_recipient(), &display_recipient);
345        assert_eq!(message.id(), id);
346        assert_eq!(message.is_me_message(), is_me_message);
347        assert_eq!(message.recipient_id(), recipient_id);
348        assert_eq!(message.sender_email(), sender_email);
349        assert_eq!(message.sender_full_name(), sender_full_name);
350        assert_eq!(message.sender_id(), sender_id);
351        assert_eq!(message.sender_realm_str(), sender_realm_str);
352        assert_eq!(message.subject(), subject);
353        assert_eq!(message.timestamp(), timestamp);
354        assert_eq!(message.msg_type(), msg_type);
355
356        assert_eq!(serde_json::to_string(&message).unwrap(), message_json);
357        assert_eq!(
358            serde_json::from_str::<Message>(&message_json).unwrap(),
359            message
360        );
361    }
362
363    #[test]
364    fn test_message_full() {
365        let avatar_url = "https://example.com/avatar";
366        let client = "client";
367        let content = "content";
368        let content_type = ContentType::Markdown;
369        let display_recipient = DisplayRecipient::Channel("recipient channel".into());
370        let id = 1;
371        let edit_history = [EditHistory::new()];
372        let is_me_message = false;
373        let last_edit_timestamp = 2;
374        let last_moved_timestamp = 3;
375        let reactions = [Reaction::new()];
376        let recipient_id = 4;
377        let sender_email = "sender@example.com";
378        let sender_full_name = "sender full name";
379        let sender_id = 5;
380        let sender_realm_str = "sender realm";
381        let stream_id = 6;
382        let subject = "test subject";
383        let submessages = [Submessage::new()];
384        let timestamp = 7;
385        let msg_type = MessageType::Channel;
386        let flags = [Flag::Historical];
387        let match_content = "match content";
388        let match_subject = "match subject";
389
390        let message = Message::new()
391            .with_avatar_url(avatar_url)
392            .with_client(client)
393            .with_content(content)
394            .with_content_type(content_type)
395            .with_display_recipient(&display_recipient)
396            .with_id(id)
397            .with_edit_history(edit_history.as_ref())
398            .with_is_me_message(is_me_message)
399            .with_last_edit_timestamp(last_edit_timestamp)
400            .with_last_moved_timestamp(last_moved_timestamp)
401            .with_reactions(reactions.as_ref())
402            .with_recipient_id(recipient_id)
403            .with_sender_email(sender_email)
404            .with_sender_full_name(sender_full_name)
405            .with_sender_id(sender_id)
406            .with_sender_realm_str(sender_realm_str)
407            .with_stream_id(stream_id)
408            .with_subject(subject)
409            .with_submessages(submessages.as_ref())
410            .with_timestamp(timestamp)
411            .with_msg_type(msg_type)
412            .with_flags(flags.as_ref())
413            .with_match_content(match_content)
414            .with_match_subject(match_subject);
415
416        let message_json = message.to_string();
417
418        assert_eq!(message.avatar_url(), Some(avatar_url));
419        assert_eq!(message.client(), client);
420        assert_eq!(message.content(), content);
421        assert_eq!(message.content_type(), content_type);
422        assert_eq!(message.display_recipient(), &display_recipient);
423        assert_eq!(message.id(), id);
424        assert_eq!(message.edit_history(), Some(edit_history.as_ref()));
425        assert_eq!(message.is_me_message(), is_me_message);
426        assert_eq!(message.last_edit_timestamp(), Some(last_edit_timestamp));
427        assert_eq!(message.last_moved_timestamp(), Some(last_moved_timestamp));
428        assert_eq!(message.reactions(), reactions.as_ref());
429        assert_eq!(message.recipient_id(), recipient_id);
430        assert_eq!(message.sender_email(), sender_email);
431        assert_eq!(message.sender_full_name(), sender_full_name);
432        assert_eq!(message.sender_id(), sender_id);
433        assert_eq!(message.sender_realm_str(), sender_realm_str);
434        assert_eq!(message.stream_id(), Some(stream_id));
435        assert_eq!(message.subject(), subject);
436        assert_eq!(message.submessages(), submessages.as_ref());
437        assert_eq!(message.timestamp(), timestamp);
438        assert_eq!(message.msg_type(), msg_type);
439        assert_eq!(message.flags(), flags.as_ref());
440        assert_eq!(message.match_content(), Some(match_content));
441        assert_eq!(message.match_subject(), Some(match_subject));
442
443        assert_eq!(serde_json::to_string(&message).unwrap(), message_json);
444        assert_eq!(
445            serde_json::from_str::<Message>(&message_json).unwrap(),
446            message
447        );
448    }
449}