mastodon_async/status_builder/mod.rs
1mod new_status;
2
3use isolang::Language;
4
5pub use self::new_status::NewStatus;
6// For backwards compatibility:
7pub use mastodon_async_entities::visibility::Visibility;
8
9/// A builder pattern struct for constructing a status.
10///
11/// // Example
12///
13/// ```
14/// use mastodon_async::{Language, StatusBuilder};
15///
16/// let status = StatusBuilder::new()
17/// .status("a status")
18/// .sensitive(true)
19/// .spoiler_text("a CW")
20/// .language(Language::Eng)
21/// .build().unwrap();
22/// ```
23#[derive(Debug, Default, Clone, PartialEq, Eq)]
24pub struct StatusBuilder {
25 status: Option<String>,
26 in_reply_to_id: Option<String>,
27 media_ids: Option<Vec<String>>,
28 sensitive: Option<bool>,
29 spoiler_text: Option<String>,
30 content_type: Option<String>,
31 visibility: Option<Visibility>,
32 language: Option<Language>,
33}
34
35impl StatusBuilder {
36 /// Create a StatusBuilder object
37 ///
38 /// // Example
39 ///
40 /// ```rust,no_run
41 /// use mastodon_async::{entities::visibility::Visibility, prelude::*};
42 ///
43 /// let data = Data::default();
44 /// let client = Mastodon::from(data);
45 /// let status = StatusBuilder::new()
46 /// .status("a status")
47 /// .visibility(Visibility::Public)
48 /// .build()
49 /// .unwrap();
50 ///
51 /// tokio_test::block_on(async {
52 /// client.new_status(status).await.unwrap();
53 /// });
54 /// ```
55 pub fn new() -> StatusBuilder {
56 StatusBuilder::default()
57 }
58
59 /// Set the text for the post
60 ///
61 /// // Example
62 ///
63 /// ```rust
64 /// use mastodon_async::prelude::*;
65 /// let status = StatusBuilder::new().status("awoooooo").build().unwrap();
66 /// ```
67 pub fn status<I: Into<String>>(&mut self, status: I) -> &mut Self {
68 self.status = Some(status.into());
69 self
70 }
71
72 /// Set the in_reply_to_id for the post
73 ///
74 /// // Example
75 ///
76 /// ```rust
77 /// use mastodon_async::prelude::*;
78 /// let status = StatusBuilder::new()
79 /// .status("awooooo")
80 /// .in_reply_to("12345")
81 /// .build()
82 /// .unwrap();
83 /// ```
84 pub fn in_reply_to<I: Into<String>>(&mut self, id: I) -> &mut Self {
85 self.in_reply_to_id = Some(id.into());
86 self
87 }
88
89 /// Set the media_ids for the post
90 ///
91 /// // Example
92 ///
93 /// ```rust
94 /// use mastodon_async::prelude::*;
95 /// let status = StatusBuilder::new().media_ids(&["foo", "bar"]).build().unwrap();
96 /// ```
97 pub fn media_ids<S: std::fmt::Display, I: IntoIterator<Item = S>>(
98 &mut self,
99 ids: I,
100 ) -> &mut Self {
101 self.media_ids = Some(ids.into_iter().map(|s| s.to_string()).collect::<Vec<_>>());
102 self
103 }
104
105 /// Set the sensitive attribute for the post
106 ///
107 /// // Example
108 ///
109 /// ```rust
110 /// use mastodon_async::prelude::*;
111 /// let status = StatusBuilder::new()
112 /// .media_ids(&["foo", "bar"])
113 /// .sensitive(true)
114 /// .build()
115 /// .unwrap();
116 /// ```
117 pub fn spoiler_text<I: Into<String>>(&mut self, spoiler_text: I) -> &mut Self {
118 self.spoiler_text = Some(spoiler_text.into());
119 self
120 }
121
122 /// Set the content type of the post
123 ///
124 /// This is a Pleroma and Glitch-soc extension of the API.
125 ///
126 /// // Possible values
127 /// - `text/plain`
128 /// - `text/html`
129 /// - `text/markdown`
130 /// - `text/bbcode` (Pleroma only)
131 ///
132 /// The set of supported content types may vary by server.
133 ///
134 /// // Example
135 ///
136 /// ```rust
137 /// use mastodon_async::prelude::*;
138 /// let status = StatusBuilder::new()
139 /// .status("<b>thicc</b>")
140 /// .content_type("text/html")
141 /// .build()
142 /// .unwrap();
143 /// ```
144 pub fn content_type<I: Into<String>>(&mut self, content_type: I) -> &mut Self {
145 self.content_type = Some(content_type.into());
146 self
147 }
148
149 /// Set the visibility for the post
150 ///
151 /// // Example
152 ///
153 /// ```rust
154 /// use mastodon_async::{prelude::*, entities::visibility::Visibility};
155 /// let status = StatusBuilder::new()
156 /// .status("awooooooo")
157 /// .visibility(Visibility::Public)
158 /// .build()
159 /// .unwrap();
160 /// ```
161 pub fn visibility(&mut self, visibility: Visibility) -> &mut Self {
162 self.visibility = Some(visibility);
163 self
164 }
165
166 /// Set the language for the post
167 ///
168 /// // Example
169 ///
170 /// ```rust
171 /// use mastodon_async::{Language, prelude::*};
172 /// let status = StatusBuilder::new()
173 /// .status("awoo!!!!")
174 /// .language(Language::Eng)
175 /// .build()
176 /// .unwrap();
177 /// ```
178 pub fn language(&mut self, language: Language) -> &mut Self {
179 self.language = Some(language);
180 self
181 }
182
183 /// Set the status as "sensitive".
184 /// ```
185 /// use mastodon_async::StatusBuilder;
186 ///
187 /// let status = StatusBuilder::new()
188 /// .status("a sensitive matter")
189 /// .sensitive(true)
190 /// .build()
191 /// .unwrap();
192 /// ```
193 pub fn sensitive(&mut self, flag: bool) -> &mut Self {
194 self.sensitive = Some(flag);
195 self
196 }
197
198 /// Constructs a NewStatus
199 ///
200 /// // Example
201 ///
202 /// ```rust
203 /// use mastodon_async::prelude::*;
204 /// let status = StatusBuilder::new().status("awoo!").build().unwrap();
205 /// ```
206 pub fn build(&self) -> Result<NewStatus, crate::Error> {
207 if self.status.is_none() && self.media_ids.is_none() {
208 return Err(crate::Error::Other(
209 "status text or media ids are required in order to post a status".to_string(),
210 ));
211 }
212 Ok(NewStatus {
213 status: self.status.clone(),
214 in_reply_to_id: self.in_reply_to_id.clone(),
215 media_ids: self.media_ids.clone(),
216 sensitive: self.sensitive,
217 spoiler_text: self.spoiler_text.clone(),
218 visibility: self.visibility,
219 language: self.language,
220 content_type: self.content_type.clone(),
221 })
222 }
223}
224
225#[cfg(test)]
226mod tests {
227 use super::*;
228 use isolang::Language;
229 use serde_json;
230
231 #[test]
232 fn test_new() {
233 let s = StatusBuilder::new()
234 .status("a status")
235 .build()
236 .expect("Couldn't build status");
237 let expected = NewStatus {
238 status: Some("a status".to_string()),
239 in_reply_to_id: None,
240 media_ids: None,
241 sensitive: None,
242 spoiler_text: None,
243 visibility: None,
244 language: None,
245 content_type: None,
246 };
247 assert_eq!(s, expected);
248 }
249
250 #[test]
251 fn test_default_visibility() {
252 let v: Visibility = Default::default();
253 assert_eq!(v, Visibility::Public);
254 }
255
256 #[test]
257 fn test_serialize_visibility() {
258 assert_eq!(
259 serde_json::to_string(&Visibility::Direct).expect("couldn't serialize visibility"),
260 "\"direct\"".to_string()
261 );
262 assert_eq!(
263 serde_json::to_string(&Visibility::Private).expect("couldn't serialize visibility"),
264 "\"private\"".to_string()
265 );
266 assert_eq!(
267 serde_json::to_string(&Visibility::Unlisted).expect("couldn't serialize visibility"),
268 "\"unlisted\"".to_string()
269 );
270 assert_eq!(
271 serde_json::to_string(&Visibility::Public).expect("couldn't serialize visibility"),
272 "\"public\"".to_string()
273 );
274 }
275
276 #[test]
277 fn test_serialize_status() {
278 let status = StatusBuilder::new()
279 .status("a status")
280 .build()
281 .expect("Couldn't build status");
282 assert_eq!(
283 serde_json::to_string(&status).expect("Couldn't serialize status"),
284 "{\"status\":\"a status\"}".to_string()
285 );
286
287 let status = StatusBuilder::new()
288 .status("a status")
289 .language(Language::Eng)
290 .build()
291 .expect("Couldn't build status");
292 assert_eq!(
293 serde_json::to_string(&status).expect("Couldn't serialize status"),
294 "{\"status\":\"a status\",\"language\":\"eng\"}"
295 );
296 }
297}