zulip_api/message/draft.rs
1use serde::{Deserialize, Serialize};
2
3use crate::{field_access, impl_default, impl_display};
4
5/// Represents a message draft.
6///
7/// Modified from `openapi-generator-cli` output:
8///
9/// ```shell,no_build,no_run
10/// $ openapi-generator-cli generate -g rust -i ./zerver/openapi/zulip.yaml -o zulip-openapi --skip-validate-spec
11/// ```
12///
13/// ```text
14/// /*
15/// * Zulip REST API
16/// *
17/// * Powerful open source group chat
18/// *
19/// * The version of the OpenAPI document: 1.0.0
20/// *
21/// * Generated by: https://openapi-generator.tech
22/// */
23/// ```
24///
25/// See [zerver/openapi/zulip.yaml](https://github.com/zulip/zulip/blob/main/zerver/openapi/zulip.yaml) for the original OpenAPI configuration.
26///
27/// Configuration slightly modified to work with the Rust generator of [`openapi-generator-cli`](https://openapi-generator.tech).
28#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
29pub struct Draft {
30 #[serde(skip_serializing_if = "Option::is_none")]
31 id: Option<i64>,
32 #[serde(rename = "type")]
33 draft_type: DraftType,
34 to: Vec<u64>,
35 topic: String,
36 content: String,
37 #[serde(skip_serializing_if = "Option::is_none")]
38 timestamp: Option<u64>,
39}
40
41impl Draft {
42 /// Creates a new [Draft].
43 pub const fn new() -> Self {
44 Self {
45 id: None,
46 draft_type: DraftType::new(),
47 to: Vec::new(),
48 topic: String::new(),
49 content: String::new(),
50 timestamp: None,
51 }
52 }
53}
54
55field_access! {
56 Draft {
57 /// The unique ID of the draft.
58 ///
59 /// It will only used whenever the drafts are fetched.
60 /// This field should not be specified when the draft is being created or edited.
61 id: option { i64 },
62 /// A Unix timestamp (seconds only) representing when the draft was last edited.
63 ///
64 /// When creating a draft, this key need not be present and it will be filled in automatically by the server.
65 timestamp: option { u64 },
66 }
67}
68
69field_access! {
70 Draft {
71 /// The type of the draft.
72 ///
73 /// Either unaddressed (empty string), `\"stream\"`, or `\"private\"` (for one-on-one and group direct messages).
74 draft_type: DraftType,
75 }
76}
77
78field_access! {
79 Draft {
80 /// An array of the tentative target audience IDs.
81 ///
82 /// For channel messages, this should contain exactly 1 ID, the ID of the target channel.
83 /// For direct messages, this should be an array of target user IDs.
84 /// For unaddressed drafts, this is ignored, and clients should send an empty array.
85 to: cow { [u64] },
86 /// For channel message drafts, the tentative topic name.
87 ///
88 /// For direct or unaddressed messages, this will be ignored and should ideally be the empty string.
89 /// Should not contain null bytes.
90 topic: cow { str },
91 /// The body of the draft.
92 ///
93 /// Should not contain null bytes.
94 content: cow { str },
95 }
96}
97
98impl_default!(Draft);
99impl_display!(Draft);
100
101/// Represents the [Draft] type.
102#[derive(Clone, Copy, Debug, Eq, PartialEq, Deserialize, Serialize)]
103#[serde(rename_all = "snake_case")]
104pub enum DraftType {
105 #[serde(rename = "")]
106 Unaddressed,
107 Stream,
108 Private,
109}
110
111impl DraftType {
112 /// Creates a new [DraftType].
113 pub const fn new() -> Self {
114 Self::Unaddressed
115 }
116}
117
118impl_default!(DraftType);
119impl_display!(DraftType);
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124
125 #[test]
126 fn test_draft() {
127 let id = 1;
128 let draft_type = DraftType::new();
129 let to = [2u64];
130 let topic = "test topic";
131 let content = "test content";
132 let timestamp = 3;
133
134 let draft = Draft::new()
135 .with_id(id)
136 .with_draft_type(draft_type)
137 .with_to(to.as_ref())
138 .with_topic(topic)
139 .with_content(content)
140 .with_timestamp(timestamp);
141 let draft_json = draft.to_string();
142
143 assert_eq!(serde_json::to_string(&draft).unwrap(), draft_json);
144 assert_eq!(serde_json::from_str::<Draft>(&draft_json).unwrap(), draft);
145
146 assert_eq!(draft.id(), Some(id));
147 assert_eq!(draft.draft_type(), draft_type);
148 assert_eq!(draft.to(), to.as_ref());
149 assert_eq!(draft.topic(), topic);
150 assert_eq!(draft.content(), content);
151 assert_eq!(draft.timestamp(), Some(timestamp));
152 }
153}