diff options
author | D. Scott Boggs <scott@tams.tech> | 2023-01-21 04:59:32 -0500 |
---|---|---|
committer | D. Scott Boggs <scott@tams.tech> | 2023-01-21 09:08:51 -0500 |
commit | cc2128ee24452b0aa9b9f8b54abfea97ead8c636 (patch) | |
tree | 7ebbf10c48a048922023c9dd4d24b55315413a0c | |
parent | ef28d8367fee9e4f40effb47a74d37c9cd95839d (diff) |
Rewrite builders to move instead of taking a reffix/builder-style
-rw-r--r-- | Cargo.toml | 10 | ||||
-rw-r--r-- | src/apps.rs | 40 | ||||
-rw-r--r-- | src/errors.rs | 7 | ||||
-rw-r--r-- | src/mastodon.rs | 6 | ||||
-rw-r--r-- | src/registration.rs | 44 | ||||
-rw-r--r-- | src/requests/filter.rs | 20 | ||||
-rw-r--r-- | src/requests/push.rs | 53 | ||||
-rw-r--r-- | src/status_builder/mod.rs | 22 |
8 files changed, 94 insertions, 108 deletions
@@ -44,6 +44,7 @@ futures-util = "0.3.25" static_assertions = "1.1.0" percent-encoding = "2.2.0" thiserror = "1.0.38" +base64 = "0.21.0" [dependencies.parse_link_header] version = "0.3.3" @@ -89,6 +90,10 @@ features = ["macros", "io-util", "time"] version = "0.7.4" features = ["io"] +[dependencies.rand] +version = "0.8.5" +optional = true + [dev-dependencies] tokio-test = "0.4.2" futures-util = "0.3.25" @@ -106,10 +111,11 @@ features = ["async_tokio"] version = "0.13" [features] -all = ["toml", "json", "env"] +all = ["toml", "json", "env", "rand"] # default = ["reqwest/default-tls"] -default = ["reqwest/default-tls"] +default = ["rand", "reqwest/default-tls"] env = ["envy"] mt = ["tokio/rt-multi-thread"] json = [] rustls-tls = ["reqwest/rustls-tls"] +rand = ["dep:rand"] diff --git a/src/apps.rs b/src/apps.rs index 86674fe..8ddb658 100644 --- a/src/apps.rs +++ b/src/apps.rs @@ -39,9 +39,7 @@ impl App { /// ``` /// use mastodon_async::{apps::App, scopes::Scopes}; /// - /// let mut builder = App::builder(); - /// builder.client_name("mastodon-async-test"); - /// let app = builder.build().unwrap(); + /// let app = App::builder().client_name("mastodon-async-test").build().unwrap(); /// let scopes = app.scopes(); /// assert_eq!(scopes, &Scopes::read_all()); /// ``` @@ -54,9 +52,7 @@ impl App { /// ``` /// use mastodon_async::{apps::App}; /// -/// let mut builder = App::builder(); -/// builder.client_name("mastodon-async_test"); -/// let app = builder.build().unwrap(); +/// let app = App::builder().client_name("mastodon-async_test").build().unwrap(); /// ``` #[derive(Clone, Debug, Default, PartialEq, Serialize)] pub struct AppBuilder<'a> { @@ -76,7 +72,7 @@ impl<'a> AppBuilder<'a> { /// grant permission. /// /// In order to turn this builder into an App, this needs to be provided - pub fn client_name<I: Into<Cow<'a, str>>>(&mut self, name: I) -> &mut Self { + pub fn client_name<I: Into<Cow<'a, str>>>(mut self, name: I) -> Self { self.client_name = Some(name.into()); self } @@ -84,7 +80,7 @@ impl<'a> AppBuilder<'a> { /// Where the user should be redirected after authorization /// /// If none is specified, the default is `urn:ietf:wg:oauth:2.0:oob` - pub fn redirect_uris<I: Into<Cow<'a, str>>>(&mut self, uris: I) -> &mut Self { + pub fn redirect_uris<I: Into<Cow<'a, str>>>(mut self, uris: I) -> Self { self.redirect_uris = Some(uris.into()); self } @@ -92,13 +88,13 @@ impl<'a> AppBuilder<'a> { /// Permission scope of the application. /// /// IF none is specified, the default is Scopes::read_all() - pub fn scopes(&mut self, scopes: Scopes) -> &mut Self { + pub fn scopes(mut self, scopes: Scopes) -> Self { self.scopes = Some(scopes); self } /// URL to the homepage of your application. - pub fn website<I: Into<Cow<'a, str>>>(&mut self, website: I) -> &mut Self { + pub fn website<I: Into<Cow<'a, str>>>(mut self, website: I) -> Self { self.website = Some(website.into()); self } @@ -142,19 +138,18 @@ mod tests { #[test] fn test_app_scopes() { - let mut builder = App::builder(); - builder.client_name("test").scopes(Scopes::all()); + let builder = App::builder().client_name("test").scopes(Scopes::all()); let app = builder.build().expect("Couldn't build App"); assert_eq!(app.scopes(), &Scopes::all()); } #[test] fn test_app_builder_all_methods() { - let mut builder = AppBuilder::new(); - builder.client_name("foo-test"); - builder.redirect_uris("http://example.com"); - builder.scopes(Scopes::read_all() | Scopes::write_all()); - builder.website("https://example.com"); + let builder = AppBuilder::new() + .client_name("foo-test") + .redirect_uris("http://example.com") + .scopes(Scopes::read_all() | Scopes::write_all()) + .website("https://example.com"); let app = builder.build().expect("Couldn't build App"); assert_eq!( app, @@ -176,12 +171,12 @@ mod tests { #[test] #[should_panic] fn test_app_builder_build_fails_if_no_client_name_2() { - let mut builder = App::builder(); - builder + App::builder() .website("https://example.com") .redirect_uris("https://example.com") - .scopes(Scopes::all()); - builder.build().expect("no client-name"); + .scopes(Scopes::all()) + .build() + .expect("no client-name"); } #[test] @@ -200,8 +195,7 @@ mod tests { #[test] fn test_app_builder_try_into_app() { - let mut builder = App::builder(); - builder + let builder = App::builder() .client_name("foo-test") .redirect_uris("http://example.com") .scopes(Scopes::all()); diff --git a/src/errors.rs b/src/errors.rs index 1459d71..9b1abe0 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -102,6 +102,13 @@ pub enum Error { /// Error from mastodon-async-entities #[error(transparent)] Entities(#[from] mastodon_async_entities::error::Error), + /// Error decoding base64-encoded strings + #[error(transparent)] + Base64(#[from] base64::DecodeError), + /// Error from RNG + #[cfg(feature = "rand")] + #[error(transparent)] + Rand(#[from] rand::Error), /// Other errors #[error("other error: {0:?}")] Other(String), diff --git a/src/mastodon.rs b/src/mastodon.rs index 79c7580..dc5781c 100644 --- a/src/mastodon.rs +++ b/src/mastodon.rs @@ -283,7 +283,11 @@ impl Mastodon { Page::new(self.clone(), response, call_id).await } - /// Add a push notifications subscription + /// Add a Web Push API subscription to receive notifications. Each access + /// token can have one push subscription. If you create a new subscription, + /// the old subscription is deleted. + /// + /// See <https://docs.joinmastodon.org/methods/push/#create>. pub async fn add_push_subscription(&self, request: &AddPushRequest) -> Result<Subscription> { let call_id = Uuid::new_v4(); let request = request.build()?; diff --git a/src/registration.rs b/src/registration.rs index cb869a4..bd9be74 100644 --- a/src/registration.rs +++ b/src/registration.rs @@ -86,34 +86,34 @@ impl<'a> Registration<'a> { /// /// This is required, and if this isn't set then the AppBuilder::build /// method will fail - pub fn client_name<I: Into<Cow<'a, str>>>(&mut self, name: I) -> &mut Self { - self.app_builder.client_name(name.into()); + pub fn client_name<I: Into<Cow<'a, str>>>(mut self, name: I) -> Self { + self.app_builder = self.app_builder.client_name(name.into()); self } /// Sets the redirect uris that this app uses - pub fn redirect_uris<I: Into<Cow<'a, str>>>(&mut self, uris: I) -> &mut Self { - self.app_builder.redirect_uris(uris); + pub fn redirect_uris<I: Into<Cow<'a, str>>>(mut self, uris: I) -> Self { + self.app_builder = self.app_builder.redirect_uris(uris); self } /// Sets the scopes that this app requires /// /// The default for an app is Scopes::Read - pub fn scopes(&mut self, scopes: Scopes) -> &mut Self { - self.app_builder.scopes(scopes); + pub fn scopes(mut self, scopes: Scopes) -> Self { + self.app_builder = self.app_builder.scopes(scopes); self } /// Sets the optional "website" to register the app with - pub fn website<I: Into<Cow<'a, str>>>(&mut self, website: I) -> &mut Self { - self.app_builder.website(website); + pub fn website<I: Into<Cow<'a, str>>>(mut self, website: I) -> Self { + self.app_builder = self.app_builder.website(website); self } /// Forces the user to re-login (useful if you need to re-auth as a /// different user on the same instance - pub fn force_login(&mut self, force_login: bool) -> &mut Self { + pub fn force_login(mut self, force_login: bool) -> Self { self.force_login = force_login; self } @@ -124,8 +124,7 @@ impl<'a> Registration<'a> { /// use mastodon_async::{apps::App, prelude::*}; /// /// tokio_test::block_on(async { - /// let mut app = App::builder(); - /// app.client_name("mastodon-async_test"); + /// let app = App::builder().client_name("mastodon-async_test"); /// /// let registration = Registration::new("https://botsin.space") /// .register(app) @@ -407,45 +406,38 @@ mod tests { #[test] fn test_set_client_name() { - let mut r = Registration::new("https://example.com"); - r.client_name("foo-test"); + let r = Registration::new("https://example.com").client_name("foo-test"); assert_eq!(r.base, "https://example.com".to_string()); - assert_eq!( - &mut r.app_builder, - AppBuilder::new().client_name("foo-test") - ); + assert_eq!(r.app_builder, AppBuilder::new().client_name("foo-test")); } #[test] fn test_set_redirect_uris() { - let mut r = Registration::new("https://example.com"); - r.redirect_uris("https://foo.com"); + let r = Registration::new("https://example.com").redirect_uris("https://foo.com"); assert_eq!(r.base, "https://example.com".to_string()); assert_eq!( - &mut r.app_builder, + r.app_builder, AppBuilder::new().redirect_uris("https://foo.com") ); } #[test] fn test_set_scopes() { - let mut r = Registration::new("https://example.com"); - r.scopes(Scopes::all()); + let r = Registration::new("https://example.com").scopes(Scopes::all()); assert_eq!(r.base, "https://example.com".to_string()); - assert_eq!(&mut r.app_builder, AppBuilder::new().scopes(Scopes::all())); + assert_eq!(r.app_builder, AppBuilder::new().scopes(Scopes::all())); } #[test] fn test_set_website() { - let mut r = Registration::new("https://example.com"); - r.website("https://website.example.com"); + let r = Registration::new("https://example.com").website("https://website.example.com"); assert_eq!(r.base, "https://example.com".to_string()); assert_eq!( - &mut r.app_builder, + r.app_builder, AppBuilder::new().website("https://website.example.com") ); } diff --git a/src/requests/filter.rs b/src/requests/filter.rs index d3dc31b..a1e141b 100644 --- a/src/requests/filter.rs +++ b/src/requests/filter.rs @@ -32,19 +32,19 @@ impl AddFilterRequest { } /// Set `irreversible` to `true` - pub fn irreversible(&mut self) -> &mut Self { + pub fn irreversible(mut self) -> Self { self.irreversible = Some(true); self } /// Set `whole_word` to `true` - pub fn whole_word(&mut self) -> &mut Self { + pub fn whole_word(mut self) -> Self { self.whole_word = Some(true); self } /// Set `expires_in` to a duration - pub fn expires_in(&mut self, d: Duration) -> &mut Self { + pub fn expires_in(mut self, d: Duration) -> Self { self.expires_in = Some(d); self } @@ -90,8 +90,7 @@ mod tests { #[test] fn test_irreversible() { - let mut request = AddFilterRequest::new("foo", FilterContext::Home); - request.irreversible(); + let request = AddFilterRequest::new("foo", FilterContext::Home).irreversible(); assert_eq!( request, AddFilterRequest { @@ -106,8 +105,7 @@ mod tests { #[test] fn test_whole_word() { - let mut request = AddFilterRequest::new("foo", FilterContext::Home); - request.whole_word(); + let request = AddFilterRequest::new("foo", FilterContext::Home).whole_word(); assert_eq!( request, AddFilterRequest { @@ -122,8 +120,8 @@ mod tests { #[test] fn test_expires_in() { - let mut request = AddFilterRequest::new("foo", FilterContext::Home); - request.expires_in(Duration::from_secs(300)); + let request = + AddFilterRequest::new("foo", FilterContext::Home).expires_in(Duration::from_secs(300)); assert_eq!( request, AddFilterRequest { @@ -138,8 +136,8 @@ mod tests { #[test] fn test_serialize_request() { - let mut request = AddFilterRequest::new("foo", FilterContext::Home); - request.expires_in(Duration::from_secs(300)); + let request = + AddFilterRequest::new("foo", FilterContext::Home).expires_in(Duration::from_secs(300)); let ser = serde_json::to_string(&request).expect("Couldn't serialize"); assert_eq!( ser, diff --git a/src/requests/push.rs b/src/requests/push.rs index 4392c08..8b57967 100644 --- a/src/requests/push.rs +++ b/src/requests/push.rs @@ -49,8 +49,7 @@ impl Keys { /// let client = Mastodon::from(data); /// /// let keys = Keys::new("stahesuahoei293ise===", "tasecoa,nmeozka=="); -/// let mut request = AddPushRequest::new("http://example.com/push/endpoint", &keys); -/// request.follow().reblog(); +/// let request = AddPushRequest::new("http://example.com/push/endpoint", &keys).follow().reblog(); /// /// client.add_push_subscription(&request).await.unwrap(); /// }); @@ -98,7 +97,7 @@ impl AddPushRequest { /// let mut request = AddPushRequest::new(push_endpoint, &keys); /// request.follow(); /// ``` - pub fn follow(&mut self) -> &mut Self { + pub fn follow(mut self) -> Self { self.follow = Some(true); self } @@ -113,7 +112,7 @@ impl AddPushRequest { /// let mut request = AddPushRequest::new(push_endpoint, &keys); /// request.favourite(); /// ``` - pub fn favourite(&mut self) -> &mut Self { + pub fn favourite(mut self) -> Self { self.favourite = Some(true); self } @@ -128,7 +127,7 @@ impl AddPushRequest { /// let mut request = AddPushRequest::new(push_endpoint, &keys); /// request.reblog(); /// ``` - pub fn reblog(&mut self) -> &mut Self { + pub fn reblog(mut self) -> Self { self.reblog = Some(true); self } @@ -143,7 +142,7 @@ impl AddPushRequest { /// let mut request = AddPushRequest::new(push_endpoint, &keys); /// request.mention(); /// ``` - pub fn mention(&mut self) -> &mut Self { + pub fn mention(mut self) -> Self { self.mention = Some(true); self } @@ -207,9 +206,7 @@ impl AddPushRequest { /// let data = Data::default(); /// let client = Mastodon::from(data); /// -/// let mut request = UpdatePushRequest::new("foobar"); -/// request.follow(true) -/// .reblog(true); +/// let request = UpdatePushRequest::new("foobar").follow(true).reblog(true); /// /// tokio_test::block_on(async { /// client.update_push_data(&request).await.unwrap(); @@ -246,7 +243,7 @@ impl UpdatePushRequest { /// let mut request = mastodon_async::requests::UpdatePushRequest::new("foobar"); /// request.follow(true); /// ``` - pub fn follow(&mut self, follow: bool) -> &mut Self { + pub fn follow(mut self, follow: bool) -> Self { self.follow = Some(follow); self } @@ -258,7 +255,7 @@ impl UpdatePushRequest { /// let mut request = mastodon_async::requests::UpdatePushRequest::new("foobar"); /// request.favourite(true); /// ``` - pub fn favourite(&mut self, favourite: bool) -> &mut Self { + pub fn favourite(mut self, favourite: bool) -> Self { self.favourite = Some(favourite); self } @@ -271,7 +268,7 @@ impl UpdatePushRequest { /// let mut request = UpdatePushRequest::new("foobar"); /// request.reblog(true); /// ``` - pub fn reblog(&mut self, reblog: bool) -> &mut Self { + pub fn reblog(mut self, reblog: bool) -> Self { self.reblog = Some(reblog); self } @@ -284,7 +281,7 @@ impl UpdatePushRequest { /// let mut request = UpdatePushRequest::new("foobar"); /// request.mention(true); /// ``` - pub fn mention(&mut self, mention: bool) -> &mut Self { + pub fn mention(mut self, mention: bool) -> Self { self.mention = Some(mention); self } @@ -368,8 +365,7 @@ mod tests { fn test_add_push_request_follow() { let endpoint = "https://example.com/push/endpoint"; let keys = Keys::new("anetohias===", "oeatssah="); - let mut req = AddPushRequest::new(endpoint, &keys); - req.follow(); + let req = AddPushRequest::new(endpoint, &keys).follow(); assert_eq!( req, AddPushRequest { @@ -388,8 +384,7 @@ mod tests { fn test_add_push_request_favourite() { let endpoint = "https://example.com/push/endpoint"; let keys = Keys::new("anetohias===", "oeatssah="); - let mut req = AddPushRequest::new(endpoint, &keys); - req.favourite(); + let req = AddPushRequest::new(endpoint, &keys).favourite(); assert_eq!( req, AddPushRequest { @@ -407,8 +402,7 @@ mod tests { fn test_add_push_request_reblog() { let endpoint = "https://example.com/push/endpoint"; let keys = Keys::new("anetohias===", "oeatssah="); - let mut req = AddPushRequest::new(endpoint, &keys); - req.reblog(); + let req = AddPushRequest::new(endpoint, &keys).reblog(); assert_eq!( req, AddPushRequest { @@ -426,8 +420,7 @@ mod tests { fn test_add_push_request_mention() { let endpoint = "https://example.com/push/endpoint"; let keys = Keys::new("anetohias===", "oeatssah="); - let mut req = AddPushRequest::new(endpoint, &keys); - req.mention(); + let req = AddPushRequest::new(endpoint, &keys).mention(); assert_eq!( req, AddPushRequest { @@ -466,8 +459,7 @@ mod tests { fn test_add_push_request_build() { let endpoint = "https://example.com/push/endpoint"; let keys = Keys::new("anetohias===", "oeatssah="); - let mut req = AddPushRequest::new(endpoint, &keys); - req.follow().reblog(); + let req = AddPushRequest::new(endpoint, &keys).follow().reblog(); let form = req.build().expect("Couldn't build form"); assert_eq!( form, @@ -508,8 +500,7 @@ mod tests { #[test] fn test_update_push_request_follow() { - let mut req = UpdatePushRequest::new("some-id"); - req.follow(true); + let req = UpdatePushRequest::new("some-id").follow(true); assert_eq!( req, UpdatePushRequest { @@ -523,8 +514,7 @@ mod tests { } #[test] fn test_update_push_request_favourite() { - let mut req = UpdatePushRequest::new("some-id"); - req.favourite(true); + let req = UpdatePushRequest::new("some-id").favourite(true); assert_eq!( req, UpdatePushRequest { @@ -538,8 +528,7 @@ mod tests { } #[test] fn test_update_push_request_reblog() { - let mut req = UpdatePushRequest::new("some-id"); - req.reblog(true); + let req = UpdatePushRequest::new("some-id").reblog(true); assert_eq!( req, UpdatePushRequest { @@ -553,8 +542,7 @@ mod tests { } #[test] fn test_update_push_request_mention() { - let mut req = UpdatePushRequest::new("some-id"); - req.mention(true); + let req = UpdatePushRequest::new("some-id").mention(true); assert_eq!( req, UpdatePushRequest { @@ -581,8 +569,7 @@ mod tests { #[test] fn test_update_push_request_build() { - let mut req = UpdatePushRequest::new("some-id"); - req.favourite(false); + let req = UpdatePushRequest::new("some-id").favourite(false); let form = req.build(); assert_eq!( form, diff --git a/src/status_builder/mod.rs b/src/status_builder/mod.rs index 1b7a201..1b28cdd 100644 --- a/src/status_builder/mod.rs +++ b/src/status_builder/mod.rs @@ -18,7 +18,8 @@ pub use mastodon_async_entities::visibility::Visibility; /// .sensitive(true) /// .spoiler_text("a CW") /// .language(Language::Eng) -/// .build().unwrap(); +/// .build() +/// .unwrap(); /// ``` #[derive(Debug, Default, Clone, PartialEq, Eq)] pub struct StatusBuilder { @@ -64,7 +65,7 @@ impl StatusBuilder { /// use mastodon_async::prelude::*; /// let status = StatusBuilder::new().status("awoooooo").build().unwrap(); /// ``` - pub fn status<I: Into<String>>(&mut self, status: I) -> &mut Self { + pub fn status<I: Into<String>>(mut self, status: I) -> Self { self.status = Some(status.into()); self } @@ -81,7 +82,7 @@ impl StatusBuilder { /// .build() /// .unwrap(); /// ``` - pub fn in_reply_to<I: Into<String>>(&mut self, id: I) -> &mut Self { + pub fn in_reply_to<I: Into<String>>(mut self, id: I) -> Self { self.in_reply_to_id = Some(id.into()); self } @@ -94,10 +95,7 @@ impl StatusBuilder { /// use mastodon_async::prelude::*; /// let status = StatusBuilder::new().media_ids(&["foo", "bar"]).build().unwrap(); /// ``` - pub fn media_ids<S: std::fmt::Display, I: IntoIterator<Item = S>>( - &mut self, - ids: I, - ) -> &mut Self { + pub fn media_ids<S: std::fmt::Display, I: IntoIterator<Item = S>>(mut self, ids: I) -> Self { self.media_ids = Some(ids.into_iter().map(|s| s.to_string()).collect::<Vec<_>>()); self } @@ -114,7 +112,7 @@ impl StatusBuilder { /// .build() /// .unwrap(); /// ``` - pub fn spoiler_text<I: Into<String>>(&mut self, spoiler_text: I) -> &mut Self { + pub fn spoiler_text<I: Into<String>>(mut self, spoiler_text: I) -> Self { self.spoiler_text = Some(spoiler_text.into()); self } @@ -141,7 +139,7 @@ impl StatusBuilder { /// .build() /// .unwrap(); /// ``` - pub fn content_type<I: Into<String>>(&mut self, content_type: I) -> &mut Self { + pub fn content_type<I: Into<String>>(mut self, content_type: I) -> Self { self.content_type = Some(content_type.into()); self } @@ -158,7 +156,7 @@ impl StatusBuilder { /// .build() /// .unwrap(); /// ``` - pub fn visibility(&mut self, visibility: Visibility) -> &mut Self { + pub fn visibility(mut self, visibility: Visibility) -> Self { self.visibility = Some(visibility); self } @@ -175,7 +173,7 @@ impl StatusBuilder { /// .build() /// .unwrap(); /// ``` - pub fn language(&mut self, language: Language) -> &mut Self { + pub fn language(mut self, language: Language) -> Self { self.language = Some(language); self } @@ -190,7 +188,7 @@ impl StatusBuilder { /// .build() /// .unwrap(); /// ``` - pub fn sensitive(&mut self, flag: bool) -> &mut Self { + pub fn sensitive(mut self, flag: bool) -> Self { self.sensitive = Some(flag); self } |