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}