rustfmt pass

master
Paul Woolcock 6 years ago
parent d617d74fa4
commit 8636e690c3
  1. 2
      README.md
  2. 1
      examples/print_your_profile.rs
  3. 19
      examples/register.rs
  4. 1
      rustfmt.toml
  5. 58
      src/apps.rs
  6. 29
      src/entities/account.rs
  7. 3
      src/entities/attachment.rs
  8. 9
      src/entities/itemsiter.rs
  9. 35
      src/entities/mod.rs
  10. 3
      src/entities/notification.rs
  11. 2
      src/entities/status.rs
  12. 20
      src/errors.rs
  13. 325
      src/lib.rs
  14. 2
      src/macros.rs
  15. 36
      src/page.rs
  16. 23
      src/registration.rs
  17. 7
      src/requests/statuses.rs
  18. 13
      src/status_builder.rs

@ -7,7 +7,7 @@
## [Documentation](https://docs.rs/elefren/) ## [Documentation](https://docs.rs/elefren/)
A wrapper around the [API](https://github.com/tootsuite/mastodon/blob/master/docs/Using-the-API/API.md#tag) for [Mastodon](https://mastodon.social/) A wrapper around the [API](https://github.com/tootsuite/documentation/blob/master/docs/Using-the-API/API.md#tag) for [Mastodon](https://mastodon.social/)
```rust ```rust
extern crate elefren; extern crate elefren;

@ -3,7 +3,6 @@ mod register;
use register::MastodonClient; use register::MastodonClient;
use std::error; use std::error;
fn main() -> Result<(), Box<error::Error>> { fn main() -> Result<(), Box<error::Error>> {
let mastodon = register::get_mastodon_data()?; let mastodon = register::get_mastodon_data()?;
let you = mastodon.verify_credentials()?; let you = mastodon.verify_credentials()?;

@ -3,19 +3,12 @@ extern crate toml;
pub use self::elefren::{Data, MastodonClient}; pub use self::elefren::{Data, MastodonClient};
use std::{ use std::{error::Error, fs, io};
error::Error,
fs,
io,
};
use self::elefren::{ use self::elefren::{
apps::{ apps::{App, Scopes},
App,
Scopes
},
Mastodon, Mastodon,
Registration Registration,
}; };
#[allow(dead_code)] #[allow(dead_code)]
@ -24,7 +17,6 @@ fn main() -> Result<(), Box<Error>> {
Ok(()) Ok(())
} }
#[allow(dead_code)] #[allow(dead_code)]
pub fn get_mastodon_data() -> Result<Mastodon, Box<Error>> { pub fn get_mastodon_data() -> Result<Mastodon, Box<Error>> {
if let Ok(config) = fs::read_to_string("mastodon-data.toml") { if let Ok(config) = fs::read_to_string("mastodon-data.toml") {
@ -38,8 +30,8 @@ pub fn get_mastodon_data() -> Result<Mastodon, Box<Error>> {
pub fn register() -> Result<Mastodon, Box<Error>> { pub fn register() -> Result<Mastodon, Box<Error>> {
let mut app = App::builder(); let mut app = App::builder();
app.client_name("elefren-examples") app.client_name("elefren-examples")
.scopes(Scopes::All) .scopes(Scopes::All)
.website("https://github.com/pwoolcoc/elefren"); .website("https://github.com/pwoolcoc/elefren");
let website = read_line("Please enter your mastodon instance url:")?; let website = read_line("Please enter your mastodon instance url:")?;
let registration = Registration::new(website.trim()); let registration = Registration::new(website.trim());
@ -67,4 +59,3 @@ pub fn read_line(message: &str) -> Result<String, Box<Error>> {
Ok(input) Ok(input)
} }

@ -1,4 +1,3 @@
indent_style = "Visual"
format_strings = true format_strings = true
format_macro_matchers = true format_macro_matchers = true
imports_layout = "HorizontalVertical" imports_layout = "HorizontalVertical"

@ -1,5 +1,4 @@
use std::fmt; use std::{borrow::Cow, fmt};
use std::borrow::Cow;
use try_from::TryInto; use try_from::TryInto;
@ -8,13 +7,8 @@ use errors::{Error, Result};
/// Provides the necessary types for registering an App and getting the /// Provides the necessary types for registering an App and getting the
/// necessary auth information /// necessary auth information
pub mod prelude { pub mod prelude {
pub use { pub use apps::{App, Scopes};
apps::{ pub use registration::Registration;
App,
Scopes
},
registration::Registration
};
} }
/// Represents an application that can be registered with a mastodon instance /// Represents an application that can be registered with a mastodon instance
@ -23,7 +17,7 @@ pub struct App {
client_name: String, client_name: String,
redirect_uris: String, redirect_uris: String,
scopes: Scopes, scopes: Scopes,
#[serde(skip_serializing_if="Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
website: Option<String>, website: Option<String>,
} }
@ -39,8 +33,8 @@ impl App {
/// Builder struct for defining your application. /// Builder struct for defining your application.
/// ``` /// ```
/// use std::error::Error;
/// use elefren::apps::prelude::*; /// use elefren::apps::prelude::*;
/// use std::error::Error;
/// ///
/// # fn main() -> Result<(), Box<Error>> { /// # fn main() -> Result<(), Box<Error>> {
/// let mut builder = App::builder(); /// let mut builder = App::builder();
@ -98,14 +92,15 @@ impl<'a> AppBuilder<'a> {
/// Will fail if no `client_name` was provided /// Will fail if no `client_name` was provided
pub fn build(self) -> Result<App> { pub fn build(self) -> Result<App> {
Ok(App { Ok(App {
client_name: self.client_name client_name: self
.ok_or_else(|| Error::MissingField("client_name"))? .client_name
.into(), .ok_or_else(|| Error::MissingField("client_name"))?
redirect_uris: self.redirect_uris .into(),
.unwrap_or_else(|| "urn:ietf:wg:oauth:2.0:oob".into()) redirect_uris: self
.into(), .redirect_uris
scopes: self.scopes .unwrap_or_else(|| "urn:ietf:wg:oauth:2.0:oob".into())
.unwrap_or_else(|| Scopes::Read), .into(),
scopes: self.scopes.unwrap_or_else(|| Scopes::Read),
website: self.website.map(|s| s.into()), website: self.website.map(|s| s.into()),
}) })
} }
@ -128,7 +123,8 @@ impl<'a> TryInto<App> for AppBuilder<'a> {
} }
/// Permission scope of the application. /// Permission scope of the application.
/// [Details on what each permission provides](//github.com/tootsuite/documentation/blob/master/Using-the-API/OAuth-details.md) /// [Details on what each permission provides][1]
/// [1]: https://github.com/tootsuite/documentation/blob/master/Using-the-API/OAuth-details.md)
#[derive(Debug, Clone, Copy, Serialize)] #[derive(Debug, Clone, Copy, Serialize)]
pub enum Scopes { pub enum Scopes {
/// All Permissions, equivalent to `read write follow` /// All Permissions, equivalent to `read write follow`
@ -157,15 +153,19 @@ pub enum Scopes {
impl fmt::Display for Scopes { impl fmt::Display for Scopes {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::Scopes::*; use self::Scopes::*;
write!(f, "{}", match *self { write!(
All => "read%20write%20follow", f,
Follow => "follow", "{}",
Read => "read", match *self {
ReadFollow => "read%20follow", All => "read%20write%20follow",
ReadWrite => "read%20write", Follow => "follow",
Write => "write", Read => "read",
WriteFollow => "write%20follow" ReadFollow => "read%20follow",
}) ReadWrite => "read%20write",
Write => "write",
WriteFollow => "write%20follow",
}
)
} }
} }

@ -2,9 +2,9 @@
use chrono::prelude::*; use chrono::prelude::*;
use reqwest::multipart::Form; use reqwest::multipart::Form;
use ::Result;
use std::path::Path;
use serde::de::{self, Deserialize, Deserializer, Unexpected}; use serde::de::{self, Deserialize, Deserializer, Unexpected};
use std::path::Path;
use Result;
/// A struct representing an Account. /// A struct representing an Account.
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
@ -57,9 +57,7 @@ pub struct Source {
note: String, note: String,
} }
fn string_or_bool<'de, D: Deserializer<'de>>(val: D) fn string_or_bool<'de, D: Deserializer<'de>>(val: D) -> ::std::result::Result<bool, D::Error> {
-> ::std::result::Result<bool, D::Error>
{
#[derive(Clone, Debug, Deserialize)] #[derive(Clone, Debug, Deserialize)]
#[serde(untagged)] #[serde(untagged)]
pub enum BoolOrString { pub enum BoolOrString {
@ -68,16 +66,19 @@ fn string_or_bool<'de, D: Deserializer<'de>>(val: D)
} }
Ok(match BoolOrString::deserialize(val)? { Ok(match BoolOrString::deserialize(val)? {
BoolOrString::Bool(b) => b, BoolOrString::Bool(b) => b,
BoolOrString::Str(ref s) => { BoolOrString::Str(ref s) => {
if s == "true" { if s == "true" {
true true
} else if s == "false" { } else if s == "false" {
false false
} else { } else {
return Err(de::Error::invalid_value(Unexpected::Str(s), &"true or false")); return Err(de::Error::invalid_value(
} Unexpected::Str(s),
&"true or false",
));
} }
},
}) })
} }

@ -6,7 +6,7 @@ pub struct Attachment {
/// ID of the attachment. /// ID of the attachment.
pub id: String, pub id: String,
/// The media type of an attachment. /// The media type of an attachment.
#[serde(rename="type")] #[serde(rename = "type")]
pub media_type: MediaType, pub media_type: MediaType,
/// URL of the locally hosted version of the image. /// URL of the locally hosted version of the image.
pub url: String, pub url: String,
@ -43,7 +43,6 @@ pub struct ImageDetails {
size: String, size: String,
/// The aspect ratio of the attachment. /// The aspect ratio of the attachment.
aspect: f64, aspect: f64,
} }
/// The type of media attachment. /// The type of media attachment.

@ -18,7 +18,7 @@ use serde::Deserialize;
/// let client = Mastodon::from(data); /// let client = Mastodon::from(data);
/// let statuses = client.statuses("user-id", None)?; /// let statuses = client.statuses("user-id", None)?;
/// for status in statuses.items_iter() { /// for status in statuses.items_iter() {
/// // do something with `status` /// // do something with `status`
/// } /// }
/// # Ok(()) /// # Ok(())
/// # } /// # }
@ -33,7 +33,7 @@ pub(crate) struct ItemsIter<'a, T: Clone + for<'de> Deserialize<'de>> {
impl<'a, T: Clone + for<'de> Deserialize<'de>> ItemsIter<'a, T> { impl<'a, T: Clone + for<'de> Deserialize<'de>> ItemsIter<'a, T> {
pub(crate) fn new(page: Page<'a, T>) -> ItemsIter<'a, T> { pub(crate) fn new(page: Page<'a, T>) -> ItemsIter<'a, T> {
ItemsIter { ItemsIter {
page: page, page,
buffer: vec![], buffer: vec![],
cur_idx: 0, cur_idx: 0,
use_initial: true, use_initial: true,
@ -41,8 +41,7 @@ impl<'a, T: Clone + for<'de> Deserialize<'de>> ItemsIter<'a, T> {
} }
fn need_next_page(&self) -> bool { fn need_next_page(&self) -> bool {
self.buffer.is_empty() || self.buffer.is_empty() || self.cur_idx == self.buffer.len()
self.cur_idx == self.buffer.len()
} }
fn fill_next_page(&mut self) -> Option<()> { fn fill_next_page(&mut self) -> Option<()> {
@ -61,7 +60,7 @@ impl<'a, T: Clone + for<'de> Deserialize<'de>> ItemsIter<'a, T> {
} }
} }
impl<'a, T: Clone+ for<'de> Deserialize<'de>> Iterator for ItemsIter<'a, T> { impl<'a, T: Clone + for<'de> Deserialize<'de>> Iterator for ItemsIter<'a, T> {
type Item = T; type Item = T;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {

@ -3,10 +3,10 @@ pub mod attachment;
pub mod card; pub mod card;
pub mod context; pub mod context;
pub mod instance; pub mod instance;
pub(crate) mod itemsiter;
pub mod list; pub mod list;
pub mod mention; pub mod mention;
pub mod notification; pub mod notification;
pub(crate) mod itemsiter;
pub mod relationship; pub mod relationship;
pub mod report; pub mod report;
pub mod search_result; pub mod search_result;
@ -17,19 +17,22 @@ pub mod status;
pub struct Empty {} pub struct Empty {}
pub mod prelude { pub mod prelude {
//! The purpose of this module is to alleviate imports of many common structs //! The purpose of this module is to alleviate imports of many common
//! by adding a glob import to the top of mastodon heavy modules: //! structs by adding a glob import to the top of mastodon heavy
pub use super::Empty; //! modules:
pub use super::account::{Account, CredientialsBuilder, Source}; pub use super::{
pub use super::attachment::{Attachment, MediaType}; account::{Account, CredientialsBuilder, Source},
pub use super::card::Card; attachment::{Attachment, MediaType},
pub use super::context::Context; card::Card,
pub use super::instance::*; context::Context,
pub use super::list::List; instance::*,
pub use super::mention::Mention; list::List,
pub use super::notification::Notification; mention::Mention,
pub use super::relationship::Relationship; notification::Notification,
pub use super::report::Report; relationship::Relationship,
pub use super::search_result::SearchResult; report::Report,
pub use super::status::{Application, Emoji, Status}; search_result::SearchResult,
status::{Application, Emoji, Status},
Empty,
};
} }

@ -1,8 +1,7 @@
//! Module containing all info about notifications. //! Module containing all info about notifications.
use super::{account::Account, status::Status};
use chrono::prelude::*; use chrono::prelude::*;
use super::account::Account;
use super::status::Status;
/// A struct containing info about a notification. /// A struct containing info about a notification.
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]

@ -1,7 +1,7 @@
//! Module containing all info relating to a status. //! Module containing all info relating to a status.
use chrono::prelude::*;
use super::prelude::*; use super::prelude::*;
use chrono::prelude::*;
use status_builder::Visibility; use status_builder::Visibility;
/// A status from the instance. /// A status from the instance.

@ -1,12 +1,7 @@
use std::{ use std::{error, fmt, io::Error as IoError};
fmt,
error,
io::Error as IoError
};
use json::Error as SerdeError; use json::Error as SerdeError;
use reqwest::Error as HttpError; use reqwest::{Error as HttpError, StatusCode};
use reqwest::StatusCode;
use url::ParseError as UrlError; use url::ParseError as UrlError;
/// Convience type over `std::result::Result` with `Error` as the error type. /// Convience type over `std::result::Result` with `Error` as the error type.
@ -52,11 +47,12 @@ impl fmt::Display for Error {
impl error::Error for Error { impl error::Error for Error {
fn description(&self) -> &str { fn description(&self) -> &str {
match *self { match *self {
Error::Api(ref e) => { Error::Api(ref e) => e
e.error_description.as_ref().map(|i| &**i) .error_description
.or(e.error.as_ref().map(|i| &**i)) .as_ref()
.unwrap_or("Unknown API Error") .map(|i| &**i)
}, .or(e.error.as_ref().map(|i| &**i))
.unwrap_or("Unknown API Error"),
Error::Serde(ref e) => e.description(), Error::Serde(ref e) => e.description(),
Error::Http(ref e) => e.description(), Error::Http(ref e) => e.description(),
Error::Io(ref e) => e.description(), Error::Io(ref e) => e.description(),

@ -9,14 +9,12 @@
//! # try().unwrap(); //! # try().unwrap();
//! # } //! # }
//! # fn try() -> elefren::Result<()> { //! # fn try() -> elefren::Result<()> {
//! use elefren::prelude::*; //! use elefren::{apps::prelude::*, prelude::*};
//! use elefren::apps::prelude::*;
//! //!
//! let mut app = App::builder(); //! let mut app = App::builder();
//! app.client_name("elefren_test"); //! app.client_name("elefren_test");
//! //!
//! let registration = Registration::new("https://mastodon.social") //! let registration = Registration::new("https://mastodon.social").register(app)?;
//! .register(app)?;
//! let url = registration.authorize_url()?; //! let url = registration.authorize_url()?;
//! // Here you now need to open the url in the browser //! // Here you now need to open the url in the browser
//! // And handle a the redirect url coming back with the code. //! // And handle a the redirect url coming back with the code.
@ -31,47 +29,57 @@
#![cfg_attr(test, deny(warnings))] #![cfg_attr(test, deny(warnings))]
#![cfg_attr(test, deny(missing_docs))] #![cfg_attr(test, deny(missing_docs))]
#[macro_use] extern crate serde_derive; #[macro_use]
#[macro_use] extern crate doc_comment; extern crate serde_derive;
#[macro_use] extern crate serde_json as json; #[macro_use]
extern crate doc_comment;
#[macro_use]
extern crate serde_json as json;
extern crate chrono; extern crate chrono;
extern crate reqwest; extern crate reqwest;
extern crate serde; extern crate serde;
extern crate try_from; extern crate try_from;
extern crate url; extern crate url;
use std::borrow::Cow; use std::{borrow::Cow, ops};
use std::ops;
use reqwest::{Client, Response}; use reqwest::{
use reqwest::header::{Authorization, Bearer, Headers}; header::{Authorization, Bearer, Headers},
Client,
Response,
};
use entities::prelude::*; use entities::prelude::*;
use page::Page; use page::Page;
pub use status_builder::StatusBuilder; pub use errors::{ApiError, Error, Result};
pub use requests::statuses::StatusesRequest;
pub use errors::{Result, Error, ApiError};
pub use registration::Registration; pub use registration::Registration;
pub use requests::statuses::StatusesRequest;
pub use status_builder::StatusBuilder;
/// Registering your App /// Registering your App
pub mod apps; pub mod apps;
/// Constructing a status
pub mod status_builder;
/// Entities returned from the API /// Entities returned from the API
pub mod entities; pub mod entities;
/// Registering your app.
pub mod registration;
/// Handling multiple pages of entities.
pub mod page;
/// Errors /// Errors
pub mod errors; pub mod errors;
/// Handling multiple pages of entities.
pub mod page;
/// Registering your app.
pub mod registration;
/// Requests /// Requests
pub mod requests; pub mod requests;
#[macro_use] mod macros; /// Constructing a status
pub mod status_builder;
#[macro_use]
mod macros;
/// Automatically import the things you need /// Automatically import the things you need
pub mod prelude { pub mod prelude {
pub use {Data, Mastodon, MastodonClient, StatusBuilder, StatusesRequest}; pub use Data;
pub use Mastodon;
pub use MastodonClient;
pub use StatusBuilder;
pub use StatusesRequest;
} }
/// Your mastodon application client, handles all requests to and from Mastodon. /// Your mastodon application client, handles all requests to and from Mastodon.
@ -80,7 +88,7 @@ pub struct Mastodon {
client: Client, client: Client,
headers: Headers, headers: Headers,
/// Raw data about your mastodon instance. /// Raw data about your mastodon instance.
pub data: Data pub data: Data,
} }
/// Raw data about mastodon app. Save `Data` using `serde` to prevent needing /// Raw data about mastodon app. Save `Data` using `serde` to prevent needing
@ -103,53 +111,155 @@ pub struct Data {
/// implementations might be swapped out for testing /// implementations might be swapped out for testing
#[allow(unused)] #[allow(unused)]
pub trait MastodonClient { pub trait MastodonClient {
fn favourites(&self) -> Result<Page<Status>> { unimplemented!("This method was not implemented"); } fn favourites(&self) -> Result<Page<Status>> {
fn blocks(&self) -> Result<Page<Account>> { unimplemented!("This method was not implemented"); } unimplemented!("This method was not implemented");
fn domain_blocks(&self) -> Result<Page<String>> { unimplemented!("This method was not implemented"); } }
fn follow_requests(&self) -> Result<Page<Account>> { unimplemented!("This method was not implemented"); } fn blocks(&self) -> Result<Page<Account>> {
fn get_home_timeline(&self) -> Result<Page<Status>> { unimplemented!("This method was not implemented"); } unimplemented!("This method was not implemented");
fn get_emojis(&self) -> Result<Page<Emoji>> { unimplemented!("This method was not implemented"); } }
fn mutes(&self) -> Result<Page<Account>> { unimplemented!("This method was not implemented"); } fn domain_blocks(&self) -> Result<Page<String>> {
fn notifications(&self) -> Result<Page<Notification>> { unimplemented!("This method was not implemented"); } unimplemented!("This method was not implemented");
fn reports(&self) -> Result<Page<Report>> { unimplemented!("This method was not implemented"); } }
fn followers(&self, id: &str) -> Result<Page<Account>> { unimplemented!("This method was not implemented"); } fn follow_requests(&self) -> Result<Page<Account>> {
fn following(&self) -> Result<Account> { unimplemented!("This method was not implemented"); } unimplemented!("This method was not implemented");
fn reblogged_by(&self) -> Result<Account> { unimplemented!("This method was not implemented"); } }
fn favourited_by(&self) -> Result<Account> { unimplemented!("This method was not implemented"); } fn get_home_timeline(&self) -> Result<Page<Status>> {
fn unblock_domain(&self, domain: String) -> Result<Empty> { unimplemented!("This method was not implemented"); } unimplemented!("This method was not implemented");
fn instance(&self) -> Result<Instance> { unimplemented!("This method was not implemented"); } }
fn verify_credentials(&self) -> Result<Account> { unimplemented!("This method was not implemented"); } fn get_emojis(&self) -> Result<Page<Emoji>> {
fn report(&self, account_id: &str, status_ids: Vec<&str>, comment: String) -> Result<Report> { unimplemented!("This method was not implemented"); } unimplemented!("This method was not implemented");
fn block_domain(&self, domain: String) -> Result<Empty> { unimplemented!("This method was not implemented"); } }
fn authorize_follow_request(&self, id: &str) -> Result<Empty> { unimplemented!("This method was not implemented"); } fn mutes(&self) -> Result<Page<Account>> {
fn reject_follow_request(&self, id: &str) -> Result<Empty> { unimplemented!("This method was not implemented"); } unimplemented!("This method was not implemented");
fn search(&self, q: String, resolve: bool) -> Result<SearchResult> { unimplemented!("This method was not implemented"); } }
fn follows(&self, uri: Cow<'static, str>) -> Result<Account> { unimplemented!("This method was not implemented"); } fn notifications(&self) -> Result<Page<Notification>> {
fn media(&self, file: Cow<'static, str>) -> Result<Attachment> { unimplemented!("This method was not implemented"); } unimplemented!("This method was not implemented");
fn clear_notifications(&self) -> Result<Empty> { unimplemented!("This method was not implemented"); } }
fn get_account(&self, id: u64) -> Result<Account> { unimplemented!("This method was not implemented"); } fn reports(&self) -> Result<Page<Report>> {
fn follow(&self, id: u64) -> Result<Account> { unimplemented!("This method was not implemented"); } unimplemented!("This method was not implemented");
fn unfollow(&self, id: u64) -> Result<Account> { unimplemented!("This method was not implemented"); } }
fn block(&self, id: u64) -> Result<Account> { unimplemented!("This method was not implemented"); } fn followers(&self, id: &str) -> Result<Page<Account>> {
fn unblock(&self, id: u64) -> Result<Account> { unimplemented!("This method was not implemented"); } unimplemented!("This method was not implemented");
fn mute(&self, id: u64) -> Result<Account> { unimplemented!("This method was not implemented"); } }
fn unmute(&self, id: u64) -> Result<Account> { unimplemented!("This method was not implemented"); } fn following(&self) -> Result<Account> {
fn get_notification(&self, id: u64) -> Result<Notification> { unimplemented!("This method was not implemented"); } unimplemented!("This method was not implemented");
fn get_status(&self, id: u64) -> Result<Status> { unimplemented!("This method was not implemented"); } }
fn get_context(&self, id: u64) -> Result<Context> { unimplemented!("This method was not implemented"); } fn reblogged_by(&self) -> Result<Account> {
fn get_card(&self, id: u64) -> Result<Card> { unimplemented!("This method was not implemented"); } unimplemented!("This method was not implemented");
fn reblog(&self, id: u64) -> Result<Status> { unimplemented!("This method was not implemented"); } }
fn unreblog(&self, id: u64) -> Result<Status> { unimplemented!("This method was not implemented"); } fn favourited_by(&self) -> Result<Account> {
fn favourite(&self, id: u64) -> Result<Status> { unimplemented!("This method was not implemented"); } unimplemented!("This method was not implemented");
fn unfavourite(&self, id: u64) -> Result<Status> { unimplemented!("This method was not implemented"); } }
fn delete_status(&self, id: u64) -> Result<Empty> { unimplemented!("This method was not implemented"); } fn unblock_domain(&self, domain: String) -> Result<Empty> {
fn update_credentials(&self, changes: CredientialsBuilder) -> Result<Account> { unimplemented!("This method was not implemented"); } unimplemented!("This method was not implemented");
fn new_status(&self, status: StatusBuilder) -> Result<Status> { unimplemented!("This method was not implemented"); } }
fn get_public_timeline(&self, local: bool) -> Result<Vec<Status>> { unimplemented!("This method was not implemented"); } fn instance(&self) -> Result<Instance> {
fn get_tagged_timeline(&self, hashtag: String, local: bool) -> Result<Vec<Status>> { unimplemented!("This method was not implemented"); } unimplemented!("This method was not implemented");
fn statuses<'a, 'b: 'a, S>(&'b self, id: &'b str, request: S) -> Result<Page<Status>> where S: Into<Option<StatusesRequest<'a>>> { unimplemented!("This method was not implemented"); } }
fn relationships(&self, ids: &[&str]) -> Result<Page<Relationship>> { unimplemented!("This method was not implemented"); } fn verify_credentials(&self) -> Result<Account> {
fn search_accounts(&self, query: &str, limit: Option<u64>, following: bool) -> Result<Page<Account>> { unimplemented!("This method was not implemented"); } unimplemented!("This method was not implemented");
}
fn report(&self, account_id: &str, status_ids: Vec<&str>, comment: String) -> Result<Report> {
unimplemented!("This method was not implemented");
}
fn block_domain(&self, domain: String) -> Result<Empty> {
unimplemented!("This method was not implemented");
}
fn authorize_follow_request(&self, id: &str) -> Result<Empty> {
unimplemented!("This method was not implemented");
}
fn reject_follow_request(&self, id: &str) -> Result<Empty> {
unimplemented!("This method was not implemented");
}
fn search(&self, q: String, resolve: bool) -> Result<SearchResult> {
unimplemented!("This method was not implemented");
}
fn follows(&self, uri: Cow<'static, str>) -> Result<Account> {
unimplemented!("This method was not implemented");
}
fn media(&self, file: Cow<'static, str>) -> Result<Attachment> {
unimplemented!("This method was not implemented");
}
fn clear_notifications(&self) -> Result<Empty> {
unimplemented!("This method was not implemented");
}
fn get_account(&self, id: u64) -> Result<Account> {
unimplemented!("This method was not implemented");
}
fn follow(&self, id: u64) -> Result<Account> {
unimplemented!("This method was not implemented");
}
fn unfollow(&self, id: u64) -> Result<Account> {
unimplemented!("This method was not implemented");
}
fn block(&self, id: u64) -> Result<Account> {
unimplemented!("This method was not implemented");
}
fn unblock(&self, id: u64) -> Result<Account> {
unimplemented!("This method was not implemented");
}
fn mute(&self, id: u64) -> Result<Account> {
unimplemented!("This method was not implemented");
}
fn unmute(&self, id: u64) -> Result<Account> {
unimplemented!("This method was not implemented");
}
fn get_notification(&self, id: u64) -> Result<Notification> {
unimplemented!("This method was not implemented");
}
fn get_status(&self, id: u64) -> Result<Status> {
unimplemented!("This method was not implemented");
}
fn get_context(&self, id: u64) -> Result<Context> {
unimplemented!("This method was not implemented");
}
fn get_card(&self, id: u64) -> Result<Card> {
unimplemented!("This method was not implemented");
}
fn reblog(&self, id: u64) -> Result<Status> {
unimplemented!("This method was not implemented");
}
fn unreblog(&self, id: u64) -> Result<Status> {
unimplemented!("This method was not implemented");
}
fn favourite(&self, id: u64) -> Result<Status> {
unimplemented!("This method was not implemented");
}
fn unfavourite(&self, id: u64) -> Result<Status> {
unimplemented!("This method was not implemented");
}
fn delete_status(&self, id: u64) -> Result<Empty> {
unimplemented!("This method was not implemented");
}
fn update_credentials(&self, changes: CredientialsBuilder) -> Result<Account> {
unimplemented!("This method was not implemented");
}
fn new_status(&self, status: StatusBuilder) -> Result<Status> {
unimplemented!("This method was not implemented");
}
fn get_public_timeline(&self, local: bool) -> Result<Vec<Status>> {
unimplemented!("This method was not implemented");
}
fn get_tagged_timeline(&self, hashtag: String, local: bool) -> Result<Vec<Status>> {
unimplemented!("This method was not implemented");
}
fn statuses<'a, 'b: 'a, S>(&'b self, id: &'b str, request: S) -> Result<Page<Status>>
where
S: Into<Option<StatusesRequest<'a>>>,
{
unimplemented!("This method was not implemented");
}
fn relationships(&self, ids: &[&str]) -> Result<Page<Relationship>> {
unimplemented!("This method was not implemented");
}
fn search_accounts(
&self,
query: &str,
limit: Option<u64>,
following: bool,
) -> Result<Page<Account>> {
unimplemented!("This method was not implemented");
}
} }
impl Mastodon { impl Mastodon {
@ -167,12 +277,13 @@ impl From<Data> for Mastodon {
fn from(data: Data) -> Mastodon { fn from(data: Data) -> Mastodon {
let mut builder = MastodonBuilder::new(); let mut builder = MastodonBuilder::new();
builder.data(data); builder.data(data);
builder.build().expect("We know `data` is present, so this should be fine") builder
.build()
.expect("We know `data` is present, so this should be fine")
} }
} }
impl MastodonClient for Mastodon { impl MastodonClient for Mastodon {
paged_routes! { paged_routes! {
(get) favourites: "favourites" => Status, (get) favourites: "favourites" => Status,
(get) blocks: "blocks" => Account, (get) blocks: "blocks" => Account,
@ -225,12 +336,11 @@ impl MastodonClient for Mastodon {
(delete) delete_status: "statuses/{}" => Empty, (delete) delete_status: "statuses/{}" => Empty,
} }
fn update_credentials(&self, changes: CredientialsBuilder) fn update_credentials(&self, changes: CredientialsBuilder) -> Result<Account> {
-> Result<Account>
{
let url = self.route("/api/v1/accounts/update_credentials"); let url = self.route("/api/v1/accounts/update_credentials");
let response = self.client.patch(&url) let response = self
.client
.patch(&url)
.headers(self.headers.clone()) .headers(self.headers.clone())
.multipart(changes.into_form()?) .multipart(changes.into_form()?)
.send()?; .send()?;
@ -248,8 +358,9 @@ impl MastodonClient for Mastodon {
/// Post a new status to the account. /// Post a new status to the account.
fn new_status(&self, status: StatusBuilder) -> Result<Status> { fn new_status(&self, status: StatusBuilder) -> Result<Status> {
let response = self
let response = self.client.post(&self.route("/api/v1/statuses")) .client
.post(&self.route("/api/v1/statuses"))
.headers(self.headers.clone()) .headers(self.headers.clone())
.json(&status) .json(&status)
.send()?; .send()?;
@ -317,14 +428,14 @@ impl MastodonClient for Mastodon {
/// # token: "".into(), /// # token: "".into(),
/// # }; /// # };
/// let client = Mastodon::from(data); /// let client = Mastodon::from(data);
/// let request = StatusesRequest::default() /// let request = StatusesRequest::default().only_media();
/// .only_media();
/// let statuses = client.statuses("user-id", request)?; /// let statuses = client.statuses("user-id", request)?;
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
fn statuses<'a, 'b: 'a, S>(&'b self, id: &'b str, request: S) -> Result<Page<Status>> fn statuses<'a, 'b: 'a, S>(&'b self, id: &'b str, request: S) -> Result<Page<Status>>
where S: Into<Option<StatusesRequest<'a>>> where
S: Into<Option<StatusesRequest<'a>>>,
{ {
let mut url = format!("{}/api/v1/accounts/{}/statuses", self.base, id); let mut url = format!("{}/api/v1/accounts/{}/statuses", self.base, id);
@ -332,9 +443,7 @@ impl MastodonClient for Mastodon {
url = format!("{}{}", url, request.to_querystring()); url = format!("{}{}", url, request.to_querystring());
} }
let response = self.client.get(&url) let response = self.client.get(&url).headers(self.headers.clone()).send()?;
.headers(self.headers.clone())
.send()?;
Page::new(self, response) Page::new(self, response)
} }
@ -356,9 +465,7 @@ impl MastodonClient for Mastodon {
url.pop(); url.pop();
} }
let response = self.client.get(&url) let response = self.client.get(&url).headers(self.headers.clone()).send()?;
.headers(self.headers.clone())
.send()?;
Page::new(self, response) Page::new(self, response)
} }
@ -366,21 +473,21 @@ impl MastodonClient for Mastodon {
/// Search for accounts by their name. /// Search for accounts by their name.
/// Will lookup an account remotely if the search term is in the /// Will lookup an account remotely if the search term is in the
/// `username@domain` format and not yet in the database. /// `username@domain` format and not yet in the database.
fn search_accounts(&self, fn search_accounts(
query: &str, &self,
limit: Option<u64>, query: &str,
following: bool) limit: Option<u64>,
-> Result<Page<Account>> following: bool,
{ ) -> Result<Page<Account>> {
let url = format!("{}/api/v1/accounts/search?q={}&limit={}&following={}", let url = format!(
self.base, "{}/api/v1/accounts/search?q={}&limit={}&following={}",
query, self.base,
limit.unwrap_or(40), query,
following); limit.unwrap_or(40),
following
let response = self.client.get(&url) );
.headers(self.headers.clone())
.send()?; let response = self.client.get(&url).headers(self.headers.clone()).send()?;
Page::new(self, response) Page::new(self, response)
} }
@ -421,12 +528,14 @@ impl MastodonBuilder {
pub fn build(self) -> Result<Mastodon> { pub fn build(self) -> Result<Mastodon> {
Ok(if let Some(data) = self.data { Ok(if let Some(data) = self.data {
let mut headers = Headers::new(); let mut headers = Headers::new();
headers.set(Authorization(Bearer { token: (*data.token).to_owned() })); headers.set(Authorization(Bearer {
token: (*data.token).to_owned(),
}));
Mastodon { Mastodon {
client: self.client.unwrap_or_else(|| Client::new()), client: self.client.unwrap_or_else(|| Client::new()),
headers: headers, headers,
data: data, data,
} }
} else { } else {
return Err(Error::DataMissing); return Err(Error::DataMissing);
@ -436,9 +545,7 @@ impl MastodonBuilder {
// Convert the HTTP response body from JSON. Pass up deserialization errors // Convert the HTTP response body from JSON. Pass up deserialization errors
// transparently. // transparently.
fn deserialise<T: for<'de> serde::Deserialize<'de>>(mut response: Response) fn deserialise<T: for<'de> serde::Deserialize<'de>>(mut response: Response) -> Result<T> {
-> Result<T>
{
use std::io::Read; use std::io::Read;
let mut vec = Vec::new(); let mut vec = Vec::new();

@ -165,5 +165,3 @@ macro_rules! paged_routes_with_id {
route!{$($rest)*} route!{$($rest)*}
}; };
} }

@ -1,9 +1,11 @@
use super::{Mastodon, Result, deserialise}; use super::{deserialise, Mastodon, Result};
use reqwest::Response; use entities::itemsiter::ItemsIter;
use reqwest::header::{Link, RelationType}; use reqwest::{
header::{Link, RelationType},
Response,
};
use serde::Deserialize; use serde::Deserialize;
use url::Url; use url::Url;
use entities::itemsiter::ItemsIter;
pub struct Page<'a, T: for<'de> Deserialize<'de>> { pub struct Page<'a, T: for<'de> Deserialize<'de>> {
mastodon: &'a Mastodon, mastodon: &'a Mastodon,
@ -38,29 +40,32 @@ macro_rules! pages {
} }
impl<'a, T: for<'de> Deserialize<'de>> Page<'a, T> { impl<'a, T: for<'de> Deserialize<'de>> Page<'a, T> {
pages! {
next: next_page,
prev: prev_page
}
pub fn new(mastodon: &'a Mastodon, response: Response) -> Result<Self> { pub fn new(mastodon: &'a Mastodon, response: Response) -> Result<Self> {
let (prev, next) = get_links(&response)?; let (prev, next) = get_links(&response)?;
Ok(Page { Ok(Page {
initial_items: deserialise(response)?, initial_items: deserialise(response)?,
next, next,
prev, prev,
mastodon mastodon,
}) })
} }
pages! {
next: next_page,
prev: prev_page
}
} }
impl<'a, T: Clone + for<'de> Deserialize<'de>> Page<'a, T> { impl<'a, T: Clone + for<'de> Deserialize<'de>> Page<'a, T> {
/// Returns an iterator that provides a stream of `T`s /// Returns an iterator that provides a stream of `T`s
/// ///
/// This abstracts away the process of iterating over each item in a page, then making an http /// This abstracts away the process of iterating over each item in a page,
/// call, then iterating over each item in the new page, etc. The iterator provides a stream of /// then making an http call, then iterating over each item in the new
/// `T`s, calling `self.next_page()` when necessary to get more of them, until there are no more /// page, etc. The iterator provides a stream of `T`s, calling
/// items. /// `self.next_page()`
/// when necessary to get
/// more of them, until
/// there are no more items.
/// ///
/// # Example /// # Example
/// ///
@ -86,7 +91,8 @@ impl<'a, T: Clone + for<'de> Deserialize<'de>> Page<'a, T> {
/// # } /// # }
/// ``` /// ```
pub fn items_iter(self) -> impl Iterator<Item = T> + 'a pub fn items_iter(self) -> impl Iterator<Item = T> + 'a
where T: 'a where
T: 'a,
{ {
ItemsIter::new(self) ItemsIter::new(self)
} }

@ -1,8 +1,12 @@
use reqwest::Client; use reqwest::Client;
use try_from::TryInto; use try_from::TryInto;
use {Data, Error, Mastodon, MastodonBuilder, Result};
use apps::{App, Scopes}; use apps::{App, Scopes};
use Data;
use Error;
use Mastodon;
use MastodonBuilder;
use Result;
/// Handles registering your mastodon app to your instance. It is recommended /// Handles registering your mastodon app to your instance. It is recommended
/// you cache your data struct to avoid registering on every run. /// you cache your data struct to avoid registering on every run.
@ -47,8 +51,7 @@ impl Registration {
/// ```no_run /// ```no_run
/// # extern crate elefren; /// # extern crate elefren;
/// # fn main () -> elefren::Result<()> { /// # fn main () -> elefren::Result<()> {
/// use elefren::prelude::*; /// use elefren::{apps::prelude::*, prelude::*};
/// use elefren::apps::prelude::*;
/// ///
/// let mut builder = App::builder(); /// let mut builder = App::builder();
/// builder.client_name("elefren_test"); /// builder.client_name("elefren_test");
@ -67,15 +70,12 @@ impl Registration {
/// # } /// # }
/// ``` /// ```
pub fn register<I: TryInto<App>>(self, app: I) -> Result<Registered> pub fn register<I: TryInto<App>>(self, app: I) -> Result<Registered>
where Error: From<<I as TryInto<App>>::Err> where
Error: From<<I as TryInto<App>>::Err>,
{ {
let app = app.try_into()?; let app = app.try_into()?;
let url = format!("{}/api/v1/apps", self.base); let url = format!("{}/api/v1/apps", self.base);
let oauth: OAuth = self.client let oauth: OAuth = self.client.post(&url).form(&app).send()?.json()?;
.post(&url)
.form(&app)
.send()?
.json()?;
Ok(Registered { Ok(Registered {
base: self.base, base: self.base,
@ -94,10 +94,7 @@ impl Registered {
pub fn authorize_url(&self) -> Result<String> { pub fn authorize_url(&self) -> Result<String> {
let url = format!( let url = format!(
"{}/oauth/authorize?client_id={}&redirect_uri={}&scope={}&response_type=code", "{}/oauth/authorize?client_id={}&redirect_uri={}&scope={}&response_type=code",
self.base, self.base, self.client_id, self.redirect, self.scopes,
self.client_id,
self.redirect,
self.scopes,
); );
Ok(url) Ok(url)

@ -5,10 +5,7 @@ use std::borrow::Cow;
/// ``` /// ```
/// # extern crate elefren; /// # extern crate elefren;
/// # use elefren::StatusesRequest; /// # use elefren::StatusesRequest;
/// let request = StatusesRequest::new() /// let request = StatusesRequest::new().only_media().pinned().since_id("foo");
/// .only_media()
/// .pinned()
/// .since_id("foo");
/// # assert_eq!(&request.to_querystring()[..], "?only_media=1&pinned=1&since_id=foo"); /// # assert_eq!(&request.to_querystring()[..], "?only_media=1&pinned=1&since_id=foo");
/// ``` /// ```
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
@ -90,5 +87,3 @@ impl<'a> StatusesRequest<'a> {
} }
} }
} }

@ -4,19 +4,19 @@ pub struct StatusBuilder {
/// The text of the status. /// The text of the status.
pub status: String, pub status: String,
/// Ids of accounts being replied to. /// Ids of accounts being replied to.
#[serde(skip_serializing_if="Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub in_reply_to_id: Option<u64>, pub in_reply_to_id: Option<u64>,
/// Ids of media attachments being attached to the status. /// Ids of media attachments being attached to the status.
#[serde(skip_serializing_if="Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub media_ids: Option<Vec<u64>>, pub media_ids: Option<Vec<u64>>,
/// Whether current status is sensitive. /// Whether current status is sensitive.
#[serde(skip_serializing_if="Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub sensitive: Option<bool>, pub sensitive: Option<bool>,
/// Text to precede the normal status text. /// Text to precede the normal status text.
#[serde(skip_serializing_if="Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub spoiler_text: Option<String>, pub spoiler_text: Option<String>,
/// Visibility of the status, defaults to `Public`. /// Visibility of the status, defaults to `Public`.
#[serde(skip_serializing_if="Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub visibility: Option<Visibility>, pub visibility: Option<Visibility>,
} }
@ -38,7 +38,6 @@ pub enum Visibility {
} }
impl StatusBuilder { impl StatusBuilder {
/// Create a new status with text. /// Create a new status with text.
/// ``` /// ```
/// use elefren::prelude::*; /// use elefren::prelude::*;
@ -47,7 +46,7 @@ impl StatusBuilder {
/// ``` /// ```
pub fn new(status: String) -> Self { pub fn new(status: String) -> Self {
StatusBuilder { StatusBuilder {
status: status, status,
..Self::default() ..Self::default()
} }
} }

Loading…
Cancel
Save