summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorD. Scott Boggs <scott@tams.tech>2023-09-29 17:18:40 -0400
committerD. Scott Boggs <scott@tams.tech>2023-09-29 17:18:40 -0400
commit6aca4c12a54aeb6f130c1b766cf2ab8b33d774fd (patch)
tree36e142eee4a64ee3c5bc035169acabf9356f9e30
parent15168b5e318a5a246b13dbfd8d07109b183a8a81 (diff)
Refactor statuses request filters options
-rw-r--r--.vscode/settings.json1
-rw-r--r--entities/src/error.rs3
-rw-r--r--entities/src/forms/mod.rs1
-rw-r--r--entities/src/forms/status_request.rs73
-rw-r--r--examples/get_statuses.rs7
-rw-r--r--src/lib.rs4
-rw-r--r--src/mastodon.rs18
-rw-r--r--src/page.rs4
-rw-r--r--src/requests/mod.rs3
-rw-r--r--src/requests/statuses.rs583
10 files changed, 94 insertions, 603 deletions
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 16ca026..486186f 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -11,6 +11,7 @@
"isolang",
"querystring",
"reblog",
+ "reblogs",
"repr",
"reqwest",
"subscope",
diff --git a/entities/src/error.rs b/entities/src/error.rs
index 427dcaa..30a7d70 100644
--- a/entities/src/error.rs
+++ b/entities/src/error.rs
@@ -11,6 +11,9 @@ pub enum Error {
Builder(#[from] derive_builder::UninitializedFieldError),
#[error(transparent)]
UrlEncodingError(serde_urlencoded::ser::Error),
+ /// Error serializing to url-encoded string
+ #[error("error serializing to url-encoded string")]
+ UrlEncoded(#[from] serde_urlencoded::ser::Error),
}
pub type Result<T> = std::result::Result<T, Error>;
diff --git a/entities/src/forms/mod.rs b/entities/src/forms/mod.rs
index 06a7aa1..19725f4 100644
--- a/entities/src/forms/mod.rs
+++ b/entities/src/forms/mod.rs
@@ -1,5 +1,6 @@
pub mod account;
pub mod application;
pub mod oauth;
+pub mod status_request;
pub use application::{Application, ApplicationBuilder};
diff --git a/entities/src/forms/status_request.rs b/entities/src/forms/status_request.rs
new file mode 100644
index 0000000..0c11a14
--- /dev/null
+++ b/entities/src/forms/status_request.rs
@@ -0,0 +1,73 @@
+use crate::error::Result;
+use derive_builder::Builder;
+use serde::Serialize;
+
+mod bool_qs_serialize {
+ use serde::Serializer;
+
+ pub fn is_false(b: &bool) -> bool {
+ !*b
+ }
+
+ pub fn serialize<S: Serializer>(b: &bool, s: S) -> Result<S::Ok, S::Error> {
+ if *b {
+ s.serialize_i64(1)
+ } else {
+ s.serialize_i64(0)
+ }
+ }
+}
+
+#[derive(Debug, Default, Serialize, Builder)]
+#[builder(
+ derive(Debug, PartialEq),
+ build_fn(error = "crate::Error", private, name = "try_build")
+)]
+pub struct Options {
+ #[serde(skip_serializing_if = "bool_qs_serialize::is_false")]
+ #[serde(serialize_with = "bool_qs_serialize::serialize")]
+ #[builder(default)]
+ only_media: bool,
+ #[serde(skip_serializing_if = "bool_qs_serialize::is_false")]
+ #[serde(serialize_with = "bool_qs_serialize::serialize")]
+ #[builder(default)]
+ exclude_replies: bool,
+ #[serde(skip_serializing_if = "bool_qs_serialize::is_false")]
+ #[serde(serialize_with = "bool_qs_serialize::serialize")]
+ #[builder(default)]
+ pinned: bool,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ #[builder(default, setter(into, strip_option))]
+ max_id: Option<String>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ #[builder(default, setter(into, strip_option))]
+ since_id: Option<String>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ #[builder(default, setter(strip_option))]
+ limit: Option<usize>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ #[builder(default, setter(into, strip_option))]
+ min_id: Option<String>,
+ #[serde(skip_serializing_if = "bool_qs_serialize::is_false")]
+ #[serde(serialize_with = "bool_qs_serialize::serialize")]
+ #[builder(default)]
+ exclude_reblogs: bool,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ #[builder(default, setter(into, strip_option))]
+ tagged: Option<String>,
+}
+
+impl Options {
+ pub fn to_query_string(&self) -> Result<String> {
+ Ok(format!("&{}", serde_urlencoded::to_string(self)?))
+ }
+ pub fn builder() -> OptionsBuilder {
+ OptionsBuilder::default()
+ }
+}
+
+impl OptionsBuilder {
+ pub fn build(&self) -> Options {
+ self.try_build().expect("no options are required")
+ }
+}
diff --git a/examples/get_statuses.rs b/examples/get_statuses.rs
index bab117a..90b1c89 100644
--- a/examples/get_statuses.rs
+++ b/examples/get_statuses.rs
@@ -1,20 +1,19 @@
#![cfg_attr(not(feature = "toml"), allow(dead_code))]
#![cfg_attr(not(feature = "toml"), allow(unused_imports))]
mod register;
-use mastodon_async::Result;
+use mastodon_async::{errors::Result, prelude::*};
#[cfg(feature = "toml")]
async fn run() -> Result<()> {
use futures_util::StreamExt;
- use mastodon_async::StatusesRequest;
- let mut filters = StatusesRequest::new();
+ let mut filters = forms::status_request::Options::builder();
filters.limit(3);
let mastodon = register::get_mastodon_data().await?;
let you = mastodon.verify_credentials().await?;
mastodon
- .statuses(&you.id, filters)
+ .statuses(&you.id, filters.build())
.await?
.items_iter()
.take(4)
diff --git a/src/lib.rs b/src/lib.rs
index abb3039..ffa8540 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -106,7 +106,7 @@ pub use mastodon_async_entities::{
status::NewStatus, status::NewStatusBuilder, visibility::Visibility,
};
pub use registration::Registration;
-pub use requests::{AddFilterRequest, AddPushRequest, StatusesRequest, UpdatePushRequest};
+pub use requests::{AddFilterRequest, AddPushRequest, UpdatePushRequest};
/// Contains the struct that holds the client auth data
pub mod data;
@@ -133,7 +133,7 @@ pub mod polling_time;
pub mod prelude {
pub use crate::{
entities::prelude::*, Data, Mastodon, MastodonUnauthenticated, NewStatus, NewStatusBuilder,
- Registration, StatusesRequest, Visibility,
+ Registration, Visibility,
};
// Legacy alias; TODO remove for 2.0
pub use super::entities::status::NewStatusBuilder as StatusBuilder;
diff --git a/src/mastodon.rs b/src/mastodon.rs
index 5a93713..feb242c 100644
--- a/src/mastodon.rs
+++ b/src/mastodon.rs
@@ -9,7 +9,7 @@ use crate::{
errors::{Error, Result},
helpers::read_response::read_response,
polling_time::PollingTime,
- AddFilterRequest, AddPushRequest, Data, NewStatus, Page, StatusesRequest, UpdatePushRequest,
+ AddFilterRequest, AddPushRequest, Data, NewStatus, Page, UpdatePushRequest,
};
use futures::TryStream;
use reqwest::{multipart::Part, Client, RequestBuilder};
@@ -249,20 +249,20 @@ impl Mastodon {
/// tokio_test::block_on(async {
/// let data = Data::default();
/// let client = Mastodon::from(data);
- /// let mut request = StatusesRequest::new();
- /// request.only_media();
- /// let statuses = client.statuses(&AccountId::new("user-id"), request).await.unwrap();
+ /// let mut options = forms::status_request::Options::builder();
+ /// options.only_media(true);
+ /// let statuses = client.statuses(&AccountId::new("user-id"), options.build()).await.unwrap();
/// });
/// ```
- pub async fn statuses<'a, 'b: 'a>(
- &'b self,
- id: &'b AccountId,
- request: StatusesRequest<'a>,
+ pub async fn statuses(
+ &self,
+ id: &AccountId,
+ options: forms::status_request::Options,
) -> Result<Page<Status>> {
let call_id = Uuid::new_v4();
let mut url = format!("{}/api/v1/accounts/{id}/statuses", self.data.base);
- url += request.to_query_string()?.as_str();
+ url += options.to_query_string()?.as_str();
debug!(
url,
diff --git a/src/page.rs b/src/page.rs
index be02b5a..c4ad21a 100644
--- a/src/page.rs
+++ b/src/page.rs
@@ -166,13 +166,13 @@ impl<T: Clone + for<'de> Deserialize<'de> + Serialize + Debug> Page<T> {
/// ```no_run
/// use mastodon_async::prelude::*;
/// use futures_util::StreamExt;
+ /// use std::default::Default;
///
/// let data = Data::default();
/// let mastodon = Mastodon::from(data);
- /// let req = StatusesRequest::new();
///
/// tokio_test::block_on(async {
- /// let resp = mastodon.statuses(&AccountId::new("some-id"), req).await.unwrap();
+ /// let resp = mastodon.statuses(&AccountId::new("some-id"), Default::default()).await.unwrap();
/// resp.items_iter().for_each(|status| async move {
/// // do something with status
/// }).await;
diff --git a/src/requests/mod.rs b/src/requests/mod.rs
index a855c5d..b792bbe 100644
--- a/src/requests/mod.rs
+++ b/src/requests/mod.rs
@@ -2,9 +2,6 @@
pub use self::filter::AddFilterRequest;
/// Data structure for the MastodonClient::add_push_subscription method
pub use self::push::{AddPushRequest, Keys, UpdatePushRequest};
-/// Data structure for the MastodonClient::statuses method
-pub use self::statuses::StatusesRequest;
mod filter;
mod push;
-mod statuses;
diff --git a/src/requests/statuses.rs b/src/requests/statuses.rs
deleted file mode 100644
index f44ff5f..0000000
--- a/src/requests/statuses.rs
+++ /dev/null
@@ -1,583 +0,0 @@
-use crate::errors::Error;
-use serde::Serialize;
-use std::{borrow::Cow, convert::Into};
-
-mod bool_qs_serialize {
- use serde::Serializer;
-
- pub fn is_false(b: &bool) -> bool {
- !*b
- }
-
- pub fn serialize<S: Serializer>(b: &bool, s: S) -> Result<S::Ok, S::Error> {
- if *b {
- s.serialize_i64(1)
- } else {
- s.serialize_i64(0)
- }
- }
-}
-
-/// Builder for making a client.statuses() call
-///
-/// // Example
-///
-/// ```
-/// use mastodon_async::requests::StatusesRequest;
-/// let mut request = StatusesRequest::new();
-/// request.only_media().pinned().since_id("foo");
-/// assert_eq!(&request.to_query_string().expect("Couldn't serialize qs")[..], "?only_media=1&pinned=1&since_id=foo");
-/// ```
-#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
-pub struct StatusesRequest<'a> {
- #[serde(skip_serializing_if = "bool_qs_serialize::is_false")]
- #[serde(serialize_with = "bool_qs_serialize::serialize")]
- only_media: bool,
- #[serde(skip_serializing_if = "bool_qs_serialize::is_false")]
- #[serde(serialize_with = "bool_qs_serialize::serialize")]
- exclude_replies: bool,
- #[serde(skip_serializing_if = "bool_qs_serialize::is_false")]
- #[serde(serialize_with = "bool_qs_serialize::serialize")]
- pinned: bool,
- #[serde(skip_serializing_if = "Option::is_none")]
- max_id: Option<Cow<'a, str>>,
- #[serde(skip_serializing_if = "Option::is_none")]
- since_id: Option<Cow<'a, str>>,
- #[serde(skip_serializing_if = "Option::is_none")]
- limit: Option<usize>,
- #[serde(skip_serializing_if = "Option::is_none")]
- min_id: Option<Cow<'a, str>>,
-}
-
-impl<'a> From<&'a mut StatusesRequest<'a>> for Option<StatusesRequest<'a>> {
- fn from(sr: &'a mut StatusesRequest<'a>) -> Self {
- Some(StatusesRequest {
- only_media: sr.only_media,
- exclude_replies: sr.exclude_replies,
- pinned: sr.pinned,
- max_id: sr.max_id.clone(),
- since_id: sr.since_id.clone(),
- limit: sr.limit,
- min_id: sr.min_id.clone(),
- })
- }
-}
-
-impl<'a> StatusesRequest<'a> {
- /// Construct a new `StatusesRequest` object
- pub fn new() -> Self {
- Self::default()
- }
-
- /// Set the `?only_media=1` flag for the .statuses() request
- ///
- /// // Example
- ///
- /// ```
- /// use mastodon_async::requests::StatusesRequest;
- /// let mut request = StatusesRequest::new();
- /// assert_eq!(&request.only_media().to_query_string().expect("Couldn't serialize qs"), "?only_media=1");
- /// ```
- pub fn only_media(&mut self) -> &mut Self {
- self.only_media = true;
- self
- }
-
- /// Set the `?exclude_replies=1` flag for the .statuses() request
- ///
- /// // Example
- ///
- /// ```
- /// use mastodon_async::requests::StatusesRequest;
- /// let mut request = StatusesRequest::new();
- /// assert_eq!(
- /// &request
- /// .exclude_replies()
- /// .to_query_string()
- /// .expect("Couldn't serialize qs"),
- /// "?exclude_replies=1"
- /// );
- /// ```
- pub fn exclude_replies(&mut self) -> &mut Self {
- self.exclude_replies = true;
- self
- }
-
- /// Set the `?pinned=1` flag for the .statuses() request
- ///
- /// // Example
- ///
- /// ```
- /// use mastodon_async::requests::StatusesRequest;
- /// let mut request = StatusesRequest::new();
- /// assert_eq!(
- /// &request
- /// .pinned()
- /// .to_query_string()
- /// .expect("Couldn't serialize qs"),
- /// "?pinned=1"
- /// );
- /// ```
- pub fn pinned(&mut self) -> &mut Self {
- self.pinned = true;
- self
- }
-
- /// Set the `?max_id=:max_id` flag for the .statuses() request
- ///
- /// // Example
- ///
- /// ```
- /// use mastodon_async::requests::StatusesRequest;
- /// let mut request = StatusesRequest::new();
- /// assert_eq!(
- /// &request
- /// .max_id("foo")
- /// .to_query_string()
- /// .expect("Couldn't serialize qs"),
- /// "?max_id=foo"
- /// );
- /// ```
- pub fn max_id<S: Into<Cow<'a, str>>>(&mut self, max_id: S) -> &mut Self {
- self.max_id = Some(max_id.into());
- self
- }
-
- /// Set the `?since_id=:since_id` flag for the .statuses() request
- ///
- /// // Example
- ///
- /// ```
- /// use mastodon_async::requests::StatusesRequest;
- /// let mut request = StatusesRequest::new();
- /// assert_eq!(
- /// &request
- /// .since_id("foo")
- /// .to_query_string()
- /// .expect("Couldn't serialize qs"),
- /// "?since_id=foo"
- /// );
- /// ```
- pub fn since_id<S: Into<Cow<'a, str>>>(&mut self, since_id: S) -> &mut Self {
- self.since_id = Some(since_id.into());
- self
- }
-
- /// Set the `?limit=:limit` flag for the .statuses() request
- ///
- /// // Example
- ///
- /// ```
- /// use mastodon_async::requests::StatusesRequest;
- /// let mut request = StatusesRequest::new();
- /// assert_eq!(
- /// &request
- /// .limit(10)
- /// .to_query_string()
- /// .expect("Couldn't serialize qs"),
- /// "?limit=10"
- /// );
- /// ```
- pub fn limit(&mut self, limit: usize) -> &mut Self {
- self.limit = Some(limit);
- self
- }
-
- /// Set the `?min_id=:min_id` flag for the .statuses() request
- ///
- /// // Example
- ///
- /// ```
- /// use mastodon_async::requests::StatusesRequest;
- /// let mut request = StatusesRequest::new();
- /// assert_eq!(
- /// &request
- /// .min_id("foobar")
- /// .to_query_string()
- /// .expect("Couldn't serialize qs"),
- /// "?min_id=foobar"
- /// );
- /// ```
- pub fn min_id<S: Into<Cow<'a, str>>>(&mut self, min_id: S) -> &mut Self {
- self.min_id = Some(min_id.into());
- self
- }
-
- /// Serialize into a query string
- pub fn to_query_string(&self) -> Result<String, Error> {
- Ok(format!("?{}", serde_urlencoded::to_string(self)?))
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn test_new() {
- let request = StatusesRequest::new();
- assert_eq!(
- request,
- StatusesRequest {
- only_media: false,
- exclude_replies: false,
- pinned: false,
- max_id: None,
- since_id: None,
- limit: None,
- min_id: None,
- }
- );
- }
-
- #[test]
- fn test_only_media() {
- let mut request = StatusesRequest::new();
- request.only_media();
- assert_eq!(
- request,
- StatusesRequest {
- only_media: true,
- exclude_replies: false,
- pinned: false,
- max_id: None,
- since_id: None,
- limit: None,
- min_id: None,
- }
- );
- }
-
- #[test]
- fn test_exclude_replies() {
- let mut request = StatusesRequest::new();
- request.exclude_replies();
- assert_eq!(
- request,
- StatusesRequest {
- only_media: false,
- exclude_replies: true,
- pinned: false,
- max_id: None,
- since_id: None,
- limit: None,
- min_id: None,
- }
- );
- }
- #[test]
- fn test_pinned() {
- let mut request = StatusesRequest::new();
- request.pinned();
- assert_eq!(
- request,
- StatusesRequest {
- only_media: false,
- exclude_replies: false,
- pinned: true,
- max_id: None,
- since_id: None,
- limit: None,
- min_id: None,
- }
- );
- }
- #[test]
- fn test_max_id() {
- let mut request = StatusesRequest::new();
- request.max_id("foo");
- assert_eq!(
- request,
- StatusesRequest {
- only_media: false,
- exclude_replies: false,
- pinned: false,
- max_id: Some("foo".into()),
- since_id: None,
- limit: None,
- min_id: None,
- }
- );
- }
- #[test]
- fn test_since_id() {
- let mut request = StatusesRequest::new();
- request.since_id("foo");
- assert_eq!(
- request,
- StatusesRequest {
- only_media: false,
- exclude_replies: false,
- pinned: false,
- max_id: None,
- since_id: Some("foo".into()),
- limit: None,
- min_id: None,
- }
- );
- }
- #[test]
- fn test_limit() {
- let mut request = StatusesRequest::new();
- request.limit(42);
- assert_eq!(
- request,
- StatusesRequest {
- only_media: false,
- exclude_replies: false,
- pinned: false,
- max_id: None,
- since_id: None,
- limit: Some(42),
- min_id: None,
- }
- );
- }
- #[test]
- fn test_min_id() {
- let mut request = StatusesRequest::new();
- request.min_id("foo");
- assert_eq!(
- request,
- StatusesRequest {
- only_media: false,
- exclude_replies: false,
- pinned: false,
- max_id: None,
- since_id: None,
- limit: None,
- min_id: Some("foo".into()),
- }
- );
- }
- #[test]
- fn test_to_query_string() {
- macro_rules! qs_test {
- (|$r:ident| $b:block, $expected:expr) => {
- {
- let mut $r = StatusesRequest::new();
- $b
- let qs = $r.to_query_string().expect("Failed to serialize querystring");
- assert_eq!(&qs, $expected);
- }
- }
- }
-
- qs_test!(
- |request| {
- request.only_media();
- },
- "?only_media=1"
- );
- qs_test!(
- |request| {
- request.exclude_replies();
- },
- "?exclude_replies=1"
- );
- qs_test!(
- |request| {
- request.pinned();
- },
- "?pinned=1"
- );
- qs_test!(
- |request| {
- request.max_id("foo");
- },
- "?max_id=foo"
- );
- qs_test!(
- |request| {
- request.since_id("foo");
- },
- "?since_id=foo"
- );
- qs_test!(
- |request| {
- request.limit(42);
- },
- "?limit=42"
- );
- qs_test!(
- |request| {
- request.only_media().exclude_replies();
- },
- "?only_media=1&exclude_replies=1"
- );
- qs_test!(
- |request| {
- request.only_media().pinned();
- },
- "?only_media=1&pinned=1"
- );
- qs_test!(
- |request| {
- request.only_media().max_id("foo");
- },
- "?only_media=1&max_id=foo"
- );
- qs_test!(
- |request| {
- request.only_media().since_id("foo");
- },
- "?only_media=1&since_id=foo"
- );
- qs_test!(
- |request| {
- request.only_media().limit(42);
- },
- "?only_media=1&limit=42"
- );
- qs_test!(
- |request| {
- request.exclude_replies().only_media();
- },
- "?only_media=1&exclude_replies=1"
- );
- qs_test!(
- |request| {
- request.exclude_replies().pinned();
- },
- "?exclude_replies=1&pinned=1"
- );
- qs_test!(
- |request| {
- request.exclude_replies().max_id("foo");
- },
- "?exclude_replies=1&max_id=foo"
- );
- qs_test!(
- |request| {
- request.exclude_replies().since_id("foo");
- },
- "?exclude_replies=1&since_id=foo"
- );
- qs_test!(
- |request| {
- request.exclude_replies().limit(42);
- },
- "?exclude_replies=1&limit=42"
- );
- qs_test!(
- |request| {
- request.pinned().only_media();
- },
- "?only_media=1&pinned=1"
- );
- qs_test!(
- |request| {
- request.pinned().exclude_replies();
- },
- "?exclude_replies=1&pinned=1"
- );
- qs_test!(
- |request| {
- request.pinned().max_id("foo");
- },
- "?pinned=1&max_id=foo"
- );
- qs_test!(
- |request| {
- request.pinned().since_id("foo");
- },
- "?pinned=1&since_id=foo"
- );
- qs_test!(
- |request| {
- request.pinned().limit(42);
- },
- "?pinned=1&limit=42"
- );
- qs_test!(
- |request| {
- request.max_id("foo").only_media();
- },
- "?only_media=1&max_id=foo"
- );
- qs_test!(
- |request| {
- request.max_id("foo").exclude_replies();
- },
- "?exclude_replies=1&max_id=foo"
- );
- qs_test!(
- |request| {
- request.max_id("foo").pinned();
- },
- "?pinned=1&max_id=foo"
- );
- qs_test!(
- |request| {
- request.max_id("foo").since_id("foo");
- },
- "?max_id=foo&since_id=foo"
- );
- qs_test!(
- |request| {
- request.max_id("foo").limit(42);
- },
- "?max_id=foo&limit=42"
- );
- qs_test!(
- |request| {
- request.since_id("foo").only_media();
- },
- "?only_media=1&since_id=foo"
- );
- qs_test!(
- |request| {
- request.since_id("foo").exclude_replies();
- },
- "?exclude_replies=1&since_id=foo"
- );
- qs_test!(
- |request| {
- request.since_id("foo").pinned();
- },
- "?pinned=1&since_id=foo"
- );
- qs_test!(
- |request| {
- request.since_id("foo").max_id("foo");
- },
- "?max_id=foo&since_id=foo"
- );
- qs_test!(
- |request| {
- request.since_id("foo").limit(42);
- },
- "?since_id=foo&limit=42"
- );
- qs_test!(
- |request| {
- request.limit(42).only_media();
- },
- "?only_media=1&limit=42"
- );
- qs_test!(
- |request| {
- request.limit(42).exclude_replies();
- },
- "?exclude_replies=1&limit=42"
- );
- qs_test!(
- |request| {
- request.limit(42).pinned();
- },
- "?pinned=1&limit=42"
- );
- qs_test!(
- |request| {
- request.limit(42).max_id("foo");
- },
- "?max_id=foo&limit=42"
- );
- qs_test!(
- |request| {
- request.limit(42).since_id("foo");
- },
- "?since_id=foo&limit=42"
- );
- }
-}