2022-11-27 14:44:43 +00:00
|
|
|
use std::borrow::Cow;
|
|
|
|
|
2022-12-07 20:58:28 +00:00
|
|
|
use log::{as_debug, as_serde, debug, error, trace};
|
2022-12-28 14:14:21 +00:00
|
|
|
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
|
2022-12-05 13:52:48 +00:00
|
|
|
use reqwest::Client;
|
2022-12-07 20:58:28 +00:00
|
|
|
use uuid::Uuid;
|
2022-11-27 14:44:43 +00:00
|
|
|
|
2022-11-29 23:50:29 +00:00
|
|
|
use crate::{
|
|
|
|
apps::{App, AppBuilder},
|
2022-12-07 21:20:20 +00:00
|
|
|
helpers::read_response::read_response,
|
2022-12-07 20:58:28 +00:00
|
|
|
log_serde,
|
2022-11-29 23:50:29 +00:00
|
|
|
scopes::Scopes,
|
2022-12-28 14:14:21 +00:00
|
|
|
Data, Error, Mastodon, Result,
|
2022-11-29 23:50:29 +00:00
|
|
|
};
|
2022-11-27 14:44:43 +00:00
|
|
|
|
2022-12-27 14:55:59 +00:00
|
|
|
const DEFAULT_REDIRECT_URI: &str = "urn:ietf:wg:oauth:2.0:oob";
|
2022-11-27 14:44:43 +00:00
|
|
|
|
|
|
|
/// Handles registering your mastodon app to your instance. It is recommended
|
|
|
|
/// you cache your data struct to avoid registering on every run.
|
|
|
|
#[derive(Debug, Clone)]
|
2022-12-05 13:52:48 +00:00
|
|
|
pub struct Registration<'a> {
|
2022-11-27 14:44:43 +00:00
|
|
|
base: String,
|
|
|
|
client: Client,
|
|
|
|
app_builder: AppBuilder<'a>,
|
|
|
|
force_login: bool,
|
|
|
|
}
|
|
|
|
|
2022-12-07 20:58:28 +00:00
|
|
|
#[derive(Serialize, Deserialize)]
|
2022-11-27 14:44:43 +00:00
|
|
|
struct OAuth {
|
|
|
|
client_id: String,
|
|
|
|
client_secret: String,
|
|
|
|
#[serde(default = "default_redirect_uri")]
|
|
|
|
redirect_uri: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
fn default_redirect_uri() -> String {
|
|
|
|
DEFAULT_REDIRECT_URI.to_string()
|
|
|
|
}
|
|
|
|
|
2022-12-07 20:58:28 +00:00
|
|
|
#[derive(Serialize, Deserialize)]
|
2022-11-27 14:44:43 +00:00
|
|
|
struct AccessToken {
|
|
|
|
access_token: String,
|
|
|
|
}
|
|
|
|
|
2022-12-05 13:52:48 +00:00
|
|
|
impl<'a> Registration<'a> {
|
2022-11-27 14:44:43 +00:00
|
|
|
/// Construct a new registration process to the instance of the `base` url.
|
|
|
|
/// ```
|
2022-12-22 18:19:49 +00:00
|
|
|
/// use mastodon_async::prelude::*;
|
2022-11-27 14:44:43 +00:00
|
|
|
///
|
2022-11-29 23:50:29 +00:00
|
|
|
/// let registration = Registration::new("https://botsin.space");
|
2022-11-27 14:44:43 +00:00
|
|
|
/// ```
|
|
|
|
pub fn new<I: Into<String>>(base: I) -> Self {
|
2023-01-14 19:06:55 +00:00
|
|
|
Registration::new_with_client(base, Client::new())
|
2022-11-27 14:44:43 +00:00
|
|
|
}
|
2023-01-12 16:01:33 +00:00
|
|
|
|
|
|
|
/// Construct a new registration process to the instance of the `base` url,
|
|
|
|
/// using the provided [Client].
|
|
|
|
/// ```
|
|
|
|
/// use mastodon_async::prelude::*;
|
|
|
|
///
|
2023-01-14 19:43:43 +00:00
|
|
|
/// let client = reqwest::Client::builder().user_agent("my cool app").build().unwrap();
|
|
|
|
/// let registration = Registration::new_with_client("https://botsin.space", client);
|
2023-01-12 16:01:33 +00:00
|
|
|
/// ```
|
|
|
|
pub fn new_with_client<I: Into<String>>(base: I, client: Client) -> Self {
|
|
|
|
Registration {
|
|
|
|
base: base.into(),
|
|
|
|
client,
|
|
|
|
app_builder: AppBuilder::new(),
|
|
|
|
force_login: false,
|
|
|
|
}
|
|
|
|
}
|
2022-11-27 14:44:43 +00:00
|
|
|
}
|
|
|
|
|
2022-12-05 13:52:48 +00:00
|
|
|
impl<'a> Registration<'a> {
|
2022-11-27 14:44:43 +00:00
|
|
|
#[allow(dead_code)]
|
2022-12-05 13:52:48 +00:00
|
|
|
pub(crate) fn with_sender<I: Into<String>>(base: I) -> Self {
|
2022-11-27 14:44:43 +00:00
|
|
|
Registration {
|
|
|
|
base: base.into(),
|
|
|
|
client: Client::new(),
|
|
|
|
app_builder: AppBuilder::new(),
|
|
|
|
force_login: false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sets the name of this app
|
|
|
|
///
|
|
|
|
/// 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());
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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 {
|
|
|
|
self.force_login = force_login;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Register the given application
|
|
|
|
///
|
|
|
|
/// ```no_run
|
2022-12-22 18:19:49 +00:00
|
|
|
/// use mastodon_async::{apps::App, prelude::*};
|
2022-11-27 14:44:43 +00:00
|
|
|
///
|
2022-12-05 13:52:48 +00:00
|
|
|
/// tokio_test::block_on(async {
|
|
|
|
/// let mut app = App::builder();
|
2022-12-22 18:19:49 +00:00
|
|
|
/// app.client_name("mastodon-async_test");
|
2022-11-27 14:44:43 +00:00
|
|
|
///
|
2022-12-05 13:52:48 +00:00
|
|
|
/// let registration = Registration::new("https://botsin.space")
|
|
|
|
/// .register(app)
|
|
|
|
/// .await
|
|
|
|
/// .unwrap();
|
|
|
|
/// let url = registration.authorize_url().unwrap();
|
|
|
|
/// // Here you now need to open the url in the browser
|
|
|
|
/// // And handle a the redirect url coming back with the code.
|
|
|
|
/// let code = String::from("RETURNED_FROM_BROWSER");
|
|
|
|
/// let mastodon = registration.complete(&code).await.unwrap();
|
2022-11-27 14:44:43 +00:00
|
|
|
///
|
2022-12-05 13:52:48 +00:00
|
|
|
/// println!("{:?}", mastodon.get_home_timeline().await.unwrap().initial_items);
|
|
|
|
/// });
|
2022-11-27 14:44:43 +00:00
|
|
|
/// ```
|
2022-12-05 13:52:48 +00:00
|
|
|
pub async fn register<I: TryInto<App>>(&mut self, app: I) -> Result<Registered>
|
2022-11-27 14:44:43 +00:00
|
|
|
where
|
2022-11-29 23:50:29 +00:00
|
|
|
Error: From<<I as TryInto<App>>::Error>,
|
2022-11-27 14:44:43 +00:00
|
|
|
{
|
|
|
|
let app = app.try_into()?;
|
2022-12-05 13:52:48 +00:00
|
|
|
let oauth = self.send_app(&app).await?;
|
2022-11-27 14:44:43 +00:00
|
|
|
|
|
|
|
Ok(Registered {
|
|
|
|
base: self.base.clone(),
|
|
|
|
client: self.client.clone(),
|
|
|
|
client_id: oauth.client_id,
|
|
|
|
client_secret: oauth.client_secret,
|
|
|
|
redirect: oauth.redirect_uri,
|
|
|
|
scopes: app.scopes().clone(),
|
|
|
|
force_login: self.force_login,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Register the application with the server from the `base` url.
|
|
|
|
///
|
|
|
|
/// ```no_run
|
2022-12-22 18:19:49 +00:00
|
|
|
/// use mastodon_async::prelude::*;
|
2022-11-27 14:44:43 +00:00
|
|
|
///
|
2022-12-05 13:52:48 +00:00
|
|
|
/// tokio_test::block_on(async {
|
|
|
|
/// let registration = Registration::new("https://botsin.space")
|
2022-12-22 18:19:49 +00:00
|
|
|
/// .client_name("mastodon-async_test")
|
2022-12-05 13:52:48 +00:00
|
|
|
/// .build()
|
|
|
|
/// .await
|
|
|
|
/// .unwrap();
|
|
|
|
/// let url = registration.authorize_url().unwrap();
|
|
|
|
/// // Here you now need to open the url in the browser
|
|
|
|
/// // And handle a the redirect url coming back with the code.
|
|
|
|
/// let code = String::from("RETURNED_FROM_BROWSER");
|
|
|
|
/// let mastodon = registration.complete(&code).await.unwrap();
|
2022-11-27 14:44:43 +00:00
|
|
|
///
|
2022-12-05 13:52:48 +00:00
|
|
|
/// println!("{:?}", mastodon.get_home_timeline().await.unwrap().initial_items);
|
|
|
|
/// });
|
2022-11-27 14:44:43 +00:00
|
|
|
/// ```
|
2022-12-05 13:52:48 +00:00
|
|
|
pub async fn build(&mut self) -> Result<Registered> {
|
2022-11-27 14:44:43 +00:00
|
|
|
let app: App = self.app_builder.clone().build()?;
|
2022-12-05 13:52:48 +00:00
|
|
|
let oauth = self.send_app(&app).await?;
|
2022-11-27 14:44:43 +00:00
|
|
|
|
|
|
|
Ok(Registered {
|
|
|
|
base: self.base.clone(),
|
|
|
|
client: self.client.clone(),
|
|
|
|
client_id: oauth.client_id,
|
|
|
|
client_secret: oauth.client_secret,
|
|
|
|
redirect: oauth.redirect_uri,
|
|
|
|
scopes: app.scopes().clone(),
|
|
|
|
force_login: self.force_login,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-12-05 13:52:48 +00:00
|
|
|
async fn send_app(&self, app: &App) -> Result<OAuth> {
|
2022-11-27 14:44:43 +00:00
|
|
|
let url = format!("{}/api/v1/apps", self.base);
|
2022-12-07 20:58:28 +00:00
|
|
|
let call_id = Uuid::new_v4();
|
|
|
|
debug!(url = url, app = as_serde!(app), call_id = as_debug!(call_id); "registering app");
|
2022-12-05 13:52:48 +00:00
|
|
|
let response = self.client.post(&url).json(&app).send().await?;
|
2022-12-07 20:58:28 +00:00
|
|
|
|
|
|
|
match response.error_for_status() {
|
|
|
|
Ok(response) => {
|
2022-12-07 21:20:20 +00:00
|
|
|
let response = read_response(response).await?;
|
2022-12-07 20:58:28 +00:00
|
|
|
debug!(
|
|
|
|
response = as_serde!(response), app = as_serde!(app),
|
|
|
|
url = url, method = stringify!($method),
|
|
|
|
call_id = as_debug!(call_id);
|
|
|
|
"received API response"
|
|
|
|
);
|
|
|
|
Ok(response)
|
2022-12-27 15:03:25 +00:00
|
|
|
}
|
2022-12-07 20:58:28 +00:00
|
|
|
Err(err) => {
|
|
|
|
error!(
|
|
|
|
err = as_debug!(err), url = url, method = stringify!($method),
|
|
|
|
call_id = as_debug!(call_id);
|
|
|
|
"error making API request"
|
|
|
|
);
|
|
|
|
Err(err.into())
|
2022-12-27 15:03:25 +00:00
|
|
|
}
|
2022-12-07 20:58:28 +00:00
|
|
|
}
|
2022-11-27 14:44:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-05 13:52:48 +00:00
|
|
|
impl Registered {
|
2022-11-27 14:44:43 +00:00
|
|
|
/// Skip having to retrieve the client id and secret from the server by
|
|
|
|
/// creating a `Registered` struct directly
|
|
|
|
///
|
2022-11-29 23:50:29 +00:00
|
|
|
/// // Example
|
2022-11-27 14:44:43 +00:00
|
|
|
///
|
|
|
|
/// ```no_run
|
2022-12-22 18:19:49 +00:00
|
|
|
/// use mastodon_async::{prelude::*, registration::Registered};
|
2022-11-27 14:44:43 +00:00
|
|
|
///
|
2022-12-05 13:52:48 +00:00
|
|
|
/// tokio_test::block_on(async {
|
|
|
|
/// let registration = Registered::from_parts(
|
|
|
|
/// "https://example.com",
|
|
|
|
/// "the-client-id",
|
|
|
|
/// "the-client-secret",
|
|
|
|
/// "https://example.com/redirect",
|
|
|
|
/// Scopes::read_all(),
|
|
|
|
/// false,
|
|
|
|
/// );
|
|
|
|
/// let url = registration.authorize_url().unwrap();
|
|
|
|
/// // Here you now need to open the url in the browser
|
|
|
|
/// // And handle a the redirect url coming back with the code.
|
|
|
|
/// let code = String::from("RETURNED_FROM_BROWSER");
|
|
|
|
/// let mastodon = registration.complete(&code).await.unwrap();
|
2022-11-27 14:44:43 +00:00
|
|
|
///
|
2022-12-05 13:52:48 +00:00
|
|
|
/// println!("{:?}", mastodon.get_home_timeline().await.unwrap().initial_items);
|
|
|
|
/// });
|
2022-11-27 14:44:43 +00:00
|
|
|
/// ```
|
|
|
|
pub fn from_parts(
|
|
|
|
base: &str,
|
|
|
|
client_id: &str,
|
|
|
|
client_secret: &str,
|
|
|
|
redirect: &str,
|
|
|
|
scopes: Scopes,
|
|
|
|
force_login: bool,
|
2022-12-05 13:52:48 +00:00
|
|
|
) -> Registered {
|
2022-11-27 14:44:43 +00:00
|
|
|
Registered {
|
|
|
|
base: base.to_string(),
|
|
|
|
client: Client::new(),
|
|
|
|
client_id: client_id.to_string(),
|
|
|
|
client_secret: client_secret.to_string(),
|
|
|
|
redirect: redirect.to_string(),
|
|
|
|
scopes,
|
|
|
|
force_login,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-05 13:52:48 +00:00
|
|
|
impl Registered {
|
2022-11-27 14:44:43 +00:00
|
|
|
/// Returns the parts of the `Registered` struct that can be used to
|
|
|
|
/// recreate another `Registered` struct
|
|
|
|
///
|
2022-11-29 23:50:29 +00:00
|
|
|
/// // Example
|
2022-11-27 14:44:43 +00:00
|
|
|
///
|
|
|
|
/// ```
|
2022-12-22 18:19:49 +00:00
|
|
|
/// use mastodon_async::{prelude::*, registration::Registered};
|
2022-11-27 14:44:43 +00:00
|
|
|
///
|
2022-11-29 23:50:29 +00:00
|
|
|
/// let orig_base = "https://example.social";
|
|
|
|
/// let orig_client_id = "some-client_id";
|
|
|
|
/// let orig_client_secret = "some-client-secret";
|
|
|
|
/// let orig_redirect = "https://example.social/redirect";
|
|
|
|
/// let orig_scopes = Scopes::all();
|
|
|
|
/// let orig_force_login = false;
|
2022-11-27 14:44:43 +00:00
|
|
|
///
|
|
|
|
/// let registered = Registered::from_parts(
|
2022-11-29 23:50:29 +00:00
|
|
|
/// orig_base,
|
|
|
|
/// orig_client_id,
|
|
|
|
/// orig_client_secret,
|
|
|
|
/// orig_redirect,
|
|
|
|
/// orig_scopes.clone(),
|
|
|
|
/// orig_force_login,
|
2022-11-27 14:44:43 +00:00
|
|
|
/// );
|
|
|
|
///
|
|
|
|
/// let (base, client_id, client_secret, redirect, scopes, force_login) = registered.into_parts();
|
|
|
|
///
|
2022-11-29 23:50:29 +00:00
|
|
|
/// assert_eq!(orig_base, &base);
|
|
|
|
/// assert_eq!(orig_client_id, &client_id);
|
|
|
|
/// assert_eq!(orig_client_secret, &client_secret);
|
|
|
|
/// assert_eq!(orig_redirect, &redirect);
|
|
|
|
/// assert_eq!(orig_scopes, scopes);
|
|
|
|
/// assert_eq!(orig_force_login, force_login);
|
2022-11-27 14:44:43 +00:00
|
|
|
/// ```
|
|
|
|
pub fn into_parts(self) -> (String, String, String, String, Scopes, bool) {
|
|
|
|
(
|
|
|
|
self.base,
|
|
|
|
self.client_id,
|
|
|
|
self.client_secret,
|
|
|
|
self.redirect,
|
|
|
|
self.scopes,
|
|
|
|
self.force_login,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2022-11-29 23:50:29 +00:00
|
|
|
/// Returns the full url needed for authorization. This needs to be opened
|
2022-11-27 14:44:43 +00:00
|
|
|
/// in a browser.
|
|
|
|
pub fn authorize_url(&self) -> Result<String> {
|
|
|
|
let scopes = format!("{}", self.scopes);
|
2022-12-28 14:14:21 +00:00
|
|
|
let scopes: String = utf8_percent_encode(&scopes, NON_ALPHANUMERIC).collect();
|
2022-11-27 14:44:43 +00:00
|
|
|
let url = if self.force_login {
|
|
|
|
format!(
|
|
|
|
"{}/oauth/authorize?client_id={}&redirect_uri={}&scope={}&force_login=true&\
|
|
|
|
response_type=code",
|
|
|
|
self.base, self.client_id, self.redirect, scopes,
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
format!(
|
|
|
|
"{}/oauth/authorize?client_id={}&redirect_uri={}&scope={}&response_type=code",
|
|
|
|
self.base, self.client_id, self.redirect, scopes,
|
|
|
|
)
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok(url)
|
|
|
|
}
|
|
|
|
|
2022-12-05 13:52:48 +00:00
|
|
|
/// Construct authentication data once token is known
|
|
|
|
fn registered(&self, token: String) -> Data {
|
|
|
|
Data {
|
|
|
|
base: self.base.clone().into(),
|
|
|
|
client_id: self.client_id.clone().into(),
|
|
|
|
client_secret: self.client_secret.clone().into(),
|
|
|
|
redirect: self.redirect.clone().into(),
|
|
|
|
token: token.into(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-27 14:44:43 +00:00
|
|
|
/// Create an access token from the client id, client secret, and code
|
2022-11-29 23:50:29 +00:00
|
|
|
/// provided by the authorization url.
|
2022-12-29 18:05:27 +00:00
|
|
|
pub async fn complete<C>(&self, code: C) -> Result<Mastodon>
|
|
|
|
where
|
|
|
|
C: AsRef<str>,
|
|
|
|
{
|
|
|
|
let url =
|
|
|
|
format!(
|
2022-11-27 14:44:43 +00:00
|
|
|
"{}/oauth/token?client_id={}&client_secret={}&code={}&grant_type=authorization_code&\
|
|
|
|
redirect_uri={}",
|
2022-12-29 18:05:27 +00:00
|
|
|
self.base, self.client_id, self.client_secret, code.as_ref(), self.redirect
|
2022-11-27 14:44:43 +00:00
|
|
|
);
|
2022-12-07 20:58:28 +00:00
|
|
|
debug!(url = url; "completing registration");
|
|
|
|
let response = self.client.post(&url).send().await?;
|
|
|
|
debug!(
|
|
|
|
status = log_serde!(response Status), url = url,
|
|
|
|
headers = log_serde!(response Headers);
|
|
|
|
"received API response"
|
|
|
|
);
|
2022-12-07 21:20:20 +00:00
|
|
|
let token: AccessToken = read_response(response).await?;
|
2022-12-07 20:58:28 +00:00
|
|
|
debug!(url = url, body = as_serde!(token); "parsed response body");
|
2022-12-05 13:52:48 +00:00
|
|
|
let data = self.registered(token.access_token);
|
2022-12-07 20:58:28 +00:00
|
|
|
trace!(auth_data = as_serde!(data); "registered");
|
2022-11-27 14:44:43 +00:00
|
|
|
|
2022-12-05 13:52:48 +00:00
|
|
|
Ok(Mastodon::new(self.client.clone(), data))
|
2022-11-27 14:44:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Represents the state of the auth flow when the app has been registered but
|
|
|
|
/// the user is not authenticated
|
|
|
|
#[derive(Debug, Clone)]
|
2022-12-05 13:52:48 +00:00
|
|
|
pub struct Registered {
|
2022-11-27 14:44:43 +00:00
|
|
|
base: String,
|
|
|
|
client: Client,
|
|
|
|
client_id: String,
|
|
|
|
client_secret: String,
|
|
|
|
redirect: String,
|
|
|
|
scopes: Scopes,
|
|
|
|
force_login: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_registration_new() {
|
|
|
|
let r = Registration::new("https://example.com");
|
|
|
|
assert_eq!(r.base, "https://example.com".to_string());
|
|
|
|
assert_eq!(r.app_builder, AppBuilder::new());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_registration_with_sender() {
|
2022-12-05 13:52:48 +00:00
|
|
|
let r = Registration::with_sender("https://example.com");
|
2022-11-27 14:44:43 +00:00
|
|
|
assert_eq!(r.base, "https://example.com".to_string());
|
|
|
|
assert_eq!(r.app_builder, AppBuilder::new());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_set_client_name() {
|
|
|
|
let mut r = Registration::new("https://example.com");
|
|
|
|
r.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")
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_set_redirect_uris() {
|
|
|
|
let mut r = Registration::new("https://example.com");
|
|
|
|
r.redirect_uris("https://foo.com");
|
|
|
|
|
|
|
|
assert_eq!(r.base, "https://example.com".to_string());
|
|
|
|
assert_eq!(
|
|
|
|
&mut 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());
|
|
|
|
|
|
|
|
assert_eq!(r.base, "https://example.com".to_string());
|
|
|
|
assert_eq!(&mut 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");
|
|
|
|
|
|
|
|
assert_eq!(r.base, "https://example.com".to_string());
|
|
|
|
assert_eq!(
|
|
|
|
&mut r.app_builder,
|
|
|
|
AppBuilder::new().website("https://website.example.com")
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_default_redirect_uri() {
|
|
|
|
assert_eq!(&default_redirect_uri()[..], DEFAULT_REDIRECT_URI);
|
|
|
|
}
|
|
|
|
}
|