feat: add authorize_connection
Also adds: src/types/entities/connection.rs, Connection and PublicConnection, src/api/users/connections.rs
This commit is contained in:
parent
6c6a87ce5b
commit
170f79bbd1
|
@ -0,0 +1,47 @@
|
|||
use reqwest::Client;
|
||||
|
||||
use crate::{
|
||||
errors::ChorusResult,
|
||||
instance::ChorusUser,
|
||||
ratelimiter::ChorusRequest,
|
||||
types::{AuthorizeConnectionReturn, AuthorizeConnectionSchema, ConnectionType, LimitType},
|
||||
};
|
||||
|
||||
impl ChorusUser {
|
||||
/// Fetches a url that can be used for authorizing a new connection.
|
||||
///
|
||||
/// # Reference
|
||||
/// See <https://docs.discord.sex/resources/user#authorize-user-connection>
|
||||
///
|
||||
/// Note: it doesn't seem to be actually unauthenticated
|
||||
pub async fn authorize_connection(
|
||||
&mut self,
|
||||
connection_type: ConnectionType,
|
||||
query_parameters: AuthorizeConnectionSchema,
|
||||
) -> ChorusResult<String> {
|
||||
let connection_type_string = serde_json::to_string(&connection_type)
|
||||
.expect("Failed to serialize connection type!")
|
||||
.replace('"', "");
|
||||
|
||||
let request = Client::new()
|
||||
.get(format!(
|
||||
"{}/connections/{}/authorize",
|
||||
self.belongs_to.read().unwrap().urls.api,
|
||||
connection_type_string
|
||||
))
|
||||
// Note: ommiting this header causes a 401 Unauthorized,
|
||||
// even though discord.sex mentions it as unauthenticated
|
||||
.header("Authorization", self.token())
|
||||
.query(&query_parameters);
|
||||
|
||||
let chorus_request = ChorusRequest {
|
||||
request,
|
||||
limit_type: LimitType::default(),
|
||||
};
|
||||
|
||||
chorus_request
|
||||
.deserialize_response::<AuthorizeConnectionReturn>(self)
|
||||
.await
|
||||
.map(|response| response.url)
|
||||
}
|
||||
}
|
|
@ -4,11 +4,13 @@
|
|||
|
||||
#![allow(unused_imports)]
|
||||
pub use channels::*;
|
||||
pub use connections::*;
|
||||
pub use guilds::*;
|
||||
pub use relationships::*;
|
||||
pub use users::*;
|
||||
|
||||
pub mod channels;
|
||||
pub mod connections;
|
||||
pub mod guilds;
|
||||
pub mod relationships;
|
||||
pub mod users;
|
||||
|
|
|
@ -15,11 +15,12 @@ use crate::{
|
|||
instance::{ChorusUser, Instance},
|
||||
ratelimiter::ChorusRequest,
|
||||
types::{
|
||||
CreateUserHarvestSchema, DeleteDisableUserSchema, GetPomeloEligibilityReturn,
|
||||
GetPomeloSuggestionsReturn, GetRecentMentionsSchema, GetUserProfileSchema, Harvest,
|
||||
HarvestBackendType, LimitType, ModifyUserNoteSchema, PublicUser, Snowflake, User,
|
||||
UserModifyProfileSchema, UserModifySchema, UserNote, UserProfile, UserProfileMetadata,
|
||||
UserSettings, VerifyUserEmailChangeResponse, VerifyUserEmailChangeSchema,
|
||||
AuthorizeConnectionSchema, ConnectionType, CreateUserHarvestSchema,
|
||||
DeleteDisableUserSchema, GetPomeloEligibilityReturn, GetPomeloSuggestionsReturn,
|
||||
GetRecentMentionsSchema, GetUserProfileSchema, Harvest, HarvestBackendType, LimitType,
|
||||
ModifyUserNoteSchema, PublicUser, Snowflake, User, UserModifyProfileSchema,
|
||||
UserModifySchema, UserNote, UserProfile, UserProfileMetadata, UserSettings,
|
||||
VerifyUserEmailChangeResponse, VerifyUserEmailChangeSchema,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,191 @@
|
|||
use std::{
|
||||
collections::HashMap,
|
||||
fmt::Display,
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_repr::{Deserialize_repr, Serialize_repr};
|
||||
|
||||
/// A 3rd party service connection to a user's account.
|
||||
///
|
||||
/// # Reference
|
||||
/// See <https://docs.discord.sex/resources/user#connection-object>
|
||||
// TODO: Should (could) this type be Updateable and Composite?
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
|
||||
pub struct Connection {
|
||||
/// The id of the account on the 3rd party service
|
||||
#[serde(rename = "id")]
|
||||
pub connected_account_id: String,
|
||||
|
||||
#[serde(rename = "type")]
|
||||
pub connection_type: ConnectionType,
|
||||
|
||||
/// The username of the connection account
|
||||
pub name: String,
|
||||
|
||||
/// If the connection is verified
|
||||
pub verified: bool,
|
||||
|
||||
/// Service specific metadata about the connection / connected account
|
||||
// FIXME: Is there a better type? As far as I see the value is always encoded as a string
|
||||
pub metadata: Option<HashMap<String, String>>,
|
||||
pub metadata_visibility: ConnectionVisibilityType,
|
||||
|
||||
/// If the connection if revoked
|
||||
pub revoked: bool,
|
||||
|
||||
// TODO: Add integrations
|
||||
pub friend_sync: bool,
|
||||
|
||||
/// Whether activities related to this connection will be shown in presence
|
||||
pub show_activity: bool,
|
||||
|
||||
/// Whether this connection has a corresponding 3rd party OAuth2 token
|
||||
pub two_way_link: bool,
|
||||
|
||||
pub visibility: ConnectionVisibilityType,
|
||||
|
||||
/// The access token for the connection account
|
||||
///
|
||||
/// Note: not included when fetching a user's connections via OAuth2
|
||||
pub access_token: Option<String>,
|
||||
}
|
||||
|
||||
/// A partial / public [Connection] type.
|
||||
///
|
||||
/// # Reference
|
||||
/// See <https://docs.discord.sex/resources/user#partial-connection-structure>
|
||||
// FIXME: Should (could) this type also be Updateable and Composite?
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||
pub struct PublicConnection {
|
||||
/// The id of the account on the 3rd party service
|
||||
#[serde(rename = "id")]
|
||||
pub connected_account_id: String,
|
||||
|
||||
#[serde(rename = "type")]
|
||||
pub connection_type: ConnectionType,
|
||||
|
||||
/// The username of the connection account
|
||||
pub name: String,
|
||||
|
||||
/// If the connection is verified
|
||||
pub verified: bool,
|
||||
|
||||
/// Service specific metadata about the connection / connected account
|
||||
// FIXME: Is there a better type? As far as I see the value is always encoded as a string
|
||||
pub metadata: Option<HashMap<String, String>>,
|
||||
}
|
||||
|
||||
impl From<Connection> for PublicConnection {
|
||||
fn from(value: Connection) -> Self {
|
||||
Self {
|
||||
connected_account_id: value.connected_account_id,
|
||||
connection_type: value.connection_type,
|
||||
name: value.name,
|
||||
verified: value.verified,
|
||||
metadata: value.metadata,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Hash, Copy, PartialOrd, Ord)]
|
||||
#[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
/// A type of connection; the service the connection is for
|
||||
///
|
||||
/// # Reference
|
||||
/// See <https://docs.discord.sex/resources/user#connection-type>
|
||||
pub enum ConnectionType {
|
||||
#[serde(rename = "amazon-music")]
|
||||
AmazonMusic,
|
||||
/// Battle.net
|
||||
BattleNet,
|
||||
/// Bungie.net
|
||||
Bungie,
|
||||
/// Discord?'s contact sync
|
||||
///
|
||||
/// (Not returned in Get User Profile or when fetching connections)
|
||||
Contacts,
|
||||
Crunchyroll,
|
||||
Domain,
|
||||
Ebay,
|
||||
EpicGames,
|
||||
Facebook,
|
||||
GitHub,
|
||||
Instagram,
|
||||
LeagueOfLegends,
|
||||
PayPal,
|
||||
/// Playstation network
|
||||
Playstation,
|
||||
Reddit,
|
||||
Roblox,
|
||||
RiotGames,
|
||||
/// Samsung Galaxy
|
||||
///
|
||||
/// Users can no longer add this service
|
||||
Samsung,
|
||||
Spotify,
|
||||
/// Users can no longer add this service
|
||||
Skype,
|
||||
Steam,
|
||||
TikTok,
|
||||
Twitch,
|
||||
Twitter,
|
||||
Xbox,
|
||||
YouTube,
|
||||
}
|
||||
|
||||
impl Display for ConnectionType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match *self {
|
||||
Self::AmazonMusic => f.write_str("Amazon Music"),
|
||||
Self::BattleNet => f.write_str("Battle.net"),
|
||||
Self::Bungie => f.write_str("Bungie.net"),
|
||||
Self::Ebay => f.write_str("eBay"),
|
||||
Self::EpicGames => f.write_str("Epic Games"),
|
||||
Self::LeagueOfLegends => f.write_str("League of Legends"),
|
||||
Self::Playstation => f.write_str("PlayStation Network"),
|
||||
Self::RiotGames => f.write_str("Riot Games"),
|
||||
Self::Samsung => f.write_str("Samsung Galaxy"),
|
||||
_ => f.write_str(format!("{:?}", self).as_str()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Serialize_repr, Deserialize_repr, Debug, Clone, Eq, PartialEq, Hash, Copy, PartialOrd, Ord,
|
||||
)]
|
||||
#[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
|
||||
#[repr(u8)]
|
||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||
/// # Reference
|
||||
/// See <https://docs.discord.sex/resources/user#visibility-type>
|
||||
pub enum ConnectionVisibilityType {
|
||||
/// Invisible to everyone except the user themselves
|
||||
None = 0,
|
||||
/// Visible to everyone
|
||||
Everyone = 1,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Hash, Copy, PartialOrd, Ord)]
|
||||
#[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
/// A type of two-way connection link
|
||||
///
|
||||
/// # Reference
|
||||
/// See <https://docs.discord.sex/resources/user#two-way-link-type>
|
||||
pub enum TwoWayLinkType {
|
||||
/// The connection is linked via web
|
||||
Web,
|
||||
/// The connection is linked via mobile
|
||||
Mobile,
|
||||
/// The connection is linked via desktop
|
||||
Desktop,
|
||||
}
|
||||
|
||||
impl Display for TwoWayLinkType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(format!("{:?}", self).as_str())
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ pub use audit_log::*;
|
|||
pub use auto_moderation::*;
|
||||
pub use channel::*;
|
||||
pub use config::*;
|
||||
pub use connection::*;
|
||||
pub use emoji::*;
|
||||
pub use guild::*;
|
||||
pub use guild_member::*;
|
||||
|
@ -50,6 +51,7 @@ mod audit_log;
|
|||
mod auto_moderation;
|
||||
mod channel;
|
||||
mod config;
|
||||
mod connection;
|
||||
mod emoji;
|
||||
mod guild;
|
||||
mod guild_member;
|
||||
|
|
|
@ -7,7 +7,7 @@ use std::collections::HashMap;
|
|||
use chrono::NaiveDate;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::types::{HarvestBackendType, Snowflake, ThemeColors};
|
||||
use crate::types::{HarvestBackendType, Snowflake, ThemeColors, TwoWayLinkType};
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
|
@ -275,3 +275,25 @@ pub(crate) struct CreateUserHarvestSchema {
|
|||
pub(crate) struct ModifyUserNoteSchema {
|
||||
pub note: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)]
|
||||
/// Query string parameters for the route GET /connections/{connection.type}/authorize
|
||||
/// ([crate::instance::ChorusUser::authorize_connection])
|
||||
///
|
||||
/// See <https://docs.discord.sex/resources/user#authorize-user-connection>
|
||||
pub struct AuthorizeConnectionSchema {
|
||||
/// The type of two-way link ([TwoWayLinkType]) to create
|
||||
pub two_way_link_type: Option<TwoWayLinkType>,
|
||||
/// The device code to use for the two-way link
|
||||
pub two_way_user_code: Option<String>,
|
||||
/// If this is a continuation of a previous authorization
|
||||
pub continuation: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
|
||||
/// Internal type for the [crate::instance::ChorusUser::authorize_connection] endpoint.
|
||||
///
|
||||
/// See <https://docs.discord.sex/resources/user#authorize-user-connection>
|
||||
pub(crate) struct AuthorizeConnectionReturn {
|
||||
pub url: String,
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue