This commit is contained in:
xystrive 2024-07-13 18:41:15 +02:00 committed by GitHub
commit ea62c35b3e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 176 additions and 85 deletions

View File

@ -24,5 +24,5 @@ async fn main() {
.await
.expect("An error occurred during the login process");
dbg!(user.belongs_to);
dbg!(&user.object.read().unwrap().username);
dbg!(&user.object.unwrap().as_ref().read().unwrap().username);
}

View File

@ -40,7 +40,7 @@ impl Instance {
user.settings = login_result.settings;
let object = User::get(&mut user, None).await?;
*user.object.write().unwrap() = object;
user.object = Some(Arc::new(RwLock::new(object)));
let mut identify = GatewayIdentifyPayload::common();
identify.token = user.token();

View File

@ -29,7 +29,7 @@ impl Instance {
let object = User::get(&mut user, None).await?;
let settings = User::get_settings(&mut user).await?;
*user.object.write().unwrap() = object;
user.object = Some(Arc::new(RwLock::new(object)));
*user.settings.write().unwrap() = settings;
let mut identify = GatewayIdentifyPayload::common();

View File

@ -49,7 +49,7 @@ impl Instance {
let object = User::get(&mut user, None).await?;
let settings = User::get_settings(&mut user).await?;
*user.object.write().unwrap() = object;
user.object = Some(Arc::new(RwLock::new(object)));
*user.settings.write().unwrap() = settings;
let mut identify = GatewayIdentifyPayload::common();

View File

@ -30,7 +30,6 @@ impl Channel {
),
None,
None,
None,
Some(user),
LimitType::Channel(channel_id),
);
@ -61,7 +60,6 @@ impl Channel {
&url,
None,
audit_log_reason.as_deref(),
None,
Some(user),
LimitType::Channel(self.id),
);
@ -101,7 +99,6 @@ impl Channel {
&url,
Some(to_string(&modify_data).unwrap()),
audit_log_reason.as_deref(),
None,
Some(user),
LimitType::Channel(channel_id),
);
@ -134,7 +131,6 @@ impl Channel {
&url,
None,
None,
None,
Some(user),
Default::default(),
);
@ -196,7 +192,6 @@ impl Channel {
&url,
None,
None,
None,
Some(user),
LimitType::Channel(self.id),
);
@ -225,7 +220,6 @@ impl Channel {
&url,
Some(to_string(&schema).unwrap()),
None,
None,
Some(user),
LimitType::Guild(guild_id),
);

View File

@ -151,7 +151,6 @@ impl Message {
.as_str(),
None,
None,
None,
Some(user),
LimitType::Channel(channel_id),
);
@ -182,7 +181,6 @@ impl Message {
.as_str(),
None,
audit_log_reason,
None,
Some(user),
LimitType::Channel(channel_id),
);
@ -209,7 +207,6 @@ impl Message {
.as_str(),
None,
audit_log_reason,
None,
Some(user),
LimitType::Channel(channel_id),
);
@ -258,7 +255,6 @@ impl Message {
.as_str(),
Some(to_string(&schema).unwrap()),
None,
None,
Some(user),
LimitType::Channel(channel_id),
);
@ -292,7 +288,6 @@ impl Message {
.as_str(),
Some(to_string(&schema).unwrap()),
None,
None,
Some(user),
LimitType::Channel(channel_id),
);
@ -321,7 +316,6 @@ impl Message {
.as_str(),
None,
None,
None,
Some(user),
LimitType::Channel(channel_id),
);
@ -348,7 +342,6 @@ impl Message {
&url,
None,
None,
None,
Some(user),
LimitType::Channel(channel_id),
);
@ -382,7 +375,6 @@ impl Message {
&url,
Some(to_string(&schema).unwrap()),
None,
None,
Some(user),
LimitType::Channel(channel_id),
);
@ -409,7 +401,6 @@ impl Message {
&url,
None,
audit_log_reason.as_deref(),
None,
Some(user),
LimitType::Channel(channel_id),
);
@ -447,7 +438,6 @@ impl Message {
.as_str(),
Some(to_string(&messages).unwrap()),
audit_log_reason.as_deref(),
None,
Some(user),
LimitType::Channel(channel_id),
);
@ -472,7 +462,6 @@ impl Message {
.as_str(),
None,
None,
None,
Some(user),
LimitType::Channel(channel_id),
);

View File

@ -83,7 +83,6 @@ impl types::Channel {
&url,
None,
None,
None,
Some(user),
LimitType::Channel(channel_id),
);

View File

@ -36,7 +36,6 @@ impl ReactionMeta {
&url,
None,
None,
None,
Some(user),
LimitType::Channel(self.channel_id),
);
@ -65,7 +64,6 @@ impl ReactionMeta {
&url,
None,
None,
None,
Some(user),
LimitType::Channel(self.channel_id),
);
@ -96,7 +94,6 @@ impl ReactionMeta {
&url,
None,
None,
None,
Some(user),
LimitType::Channel(self.channel_id),
);
@ -130,7 +127,6 @@ impl ReactionMeta {
&url,
None,
None,
None,
Some(user),
LimitType::Channel(self.channel_id),
);
@ -159,7 +155,6 @@ impl ReactionMeta {
&url,
None,
None,
None,
Some(user),
LimitType::Channel(self.channel_id),
);
@ -196,7 +191,6 @@ impl ReactionMeta {
&url,
None,
None,
None,
Some(user),
LimitType::Channel(self.channel_id),
);

View File

@ -220,7 +220,6 @@ impl Guild {
.as_str(),
None,
None,
None,
Some(user),
LimitType::Guild(guild_id),
);
@ -246,7 +245,6 @@ impl Guild {
.as_str(),
None,
None,
None,
Some(user),
LimitType::Guild(guild_id),
);
@ -279,7 +277,6 @@ impl Guild {
.as_str(),
None,
audit_log_reason.as_deref(),
None,
Some(user),
LimitType::Guild(guild_id),
);
@ -309,7 +306,6 @@ impl Guild {
.as_str(),
Some(to_string(&schema).unwrap()),
audit_log_reason.as_deref(),
None,
Some(user),
LimitType::Guild(guild_id),
);
@ -336,7 +332,6 @@ impl Guild {
.as_str(),
Some(to_string(&schema).unwrap()),
audit_log_reason.as_deref(),
None,
Some(user),
LimitType::Guild(guild_id),
);
@ -362,7 +357,6 @@ impl Guild {
.as_str(),
Some(to_string(&schema).unwrap()),
None,
None,
Some(user),
LimitType::Guild(guild_id),
);
@ -393,7 +387,6 @@ impl Guild {
&url,
None,
None,
None,
Some(user),
LimitType::Guild(guild_id),
);
@ -426,7 +419,6 @@ impl Guild {
&url,
None,
None,
None,
Some(user),
LimitType::Guild(guild_id),
);
@ -456,7 +448,6 @@ impl Guild {
.as_str(),
Some(to_string(&schema).unwrap()),
audit_log_reason.as_deref(),
None,
Some(user),
LimitType::Guild(guild_id),
);
@ -487,7 +478,6 @@ impl Guild {
&url,
None,
audit_log_reason.as_deref(),
None,
Some(user),
LimitType::Guild(guild_id),
);

View File

@ -188,7 +188,6 @@ impl types::RoleObject {
&url,
None,
audit_log_reason.as_deref(),
None,
Some(user),
LimitType::Guild(guild_id),
);

View File

@ -5,7 +5,7 @@
//! Contains all the errors that can be returned by the library.
use custom_error::custom_error;
use crate::types::WebSocketEvent;
use crate::types::{MfaRequiredSchema, WebSocketEvent};
use chorus_macros::WebSocketEvent;
custom_error! {
@ -46,7 +46,9 @@ custom_error! {
/// Malformed or unexpected response.
InvalidResponse{error: String} = "The response is malformed and cannot be processed. Error: {error}",
/// Invalid, insufficient or too many arguments provided.
InvalidArguments{error: String} = "Invalid arguments were provided. Error: {error}"
InvalidArguments{error: String} = "Invalid arguments were provided. Error: {error}",
/// The request requires MFA verification
MfaRequired {error: MfaRequiredSchema} = "Mfa verification is required to perform this action"
}
impl From<reqwest::Error> for ChorusError {

View File

@ -8,16 +8,18 @@ use std::collections::HashMap;
use std::fmt;
use std::sync::{Arc, RwLock};
use std::time::Duration;
use reqwest::Client;
use serde::{Deserialize, Serialize};
use chrono::Utc;
use crate::errors::ChorusResult;
use crate::gateway::{Gateway, GatewayHandle, GatewayOptions};
use crate::ratelimiter::ChorusRequest;
use crate::types::types::subconfigs::limits::rates::RateLimits;
use crate::types::{
GeneralConfiguration, Limit, LimitType, LimitsConfiguration, Shared, User, UserSettings,
GeneralConfiguration, Limit, LimitType, LimitsConfiguration, MfaTokenSchema, MfaVerifySchema, Shared, User, UserSettings, MfaToken
};
use crate::UrlBundle;
@ -169,9 +171,10 @@ impl fmt::Display for Token {
pub struct ChorusUser {
pub belongs_to: Shared<Instance>,
pub token: String,
pub mfa_token: Option<MfaToken>,
pub limits: Option<HashMap<LimitType, Limit>>,
pub settings: Shared<UserSettings>,
pub object: Shared<User>,
pub object: Option<Shared<User>>,
pub gateway: GatewayHandle,
}
@ -202,12 +205,13 @@ impl ChorusUser {
token: String,
limits: Option<HashMap<LimitType, Limit>>,
settings: Shared<UserSettings>,
object: Shared<User>,
object: Option<Shared<User>>,
gateway: GatewayHandle,
) -> ChorusUser {
ChorusUser {
belongs_to,
token,
mfa_token: None,
limits,
settings,
object,
@ -222,7 +226,6 @@ impl ChorusUser {
/// first.
pub(crate) async fn shell(instance: Shared<Instance>, token: String) -> ChorusUser {
let settings = Arc::new(RwLock::new(UserSettings::default()));
let object = Arc::new(RwLock::new(User::default()));
let wss_url = instance.read().unwrap().urls.wss.clone();
// Dummy gateway object
let gateway = Gateway::spawn(wss_url, GatewayOptions::default())
@ -230,6 +233,7 @@ impl ChorusUser {
.unwrap();
ChorusUser {
token,
mfa_token: None,
belongs_to: instance.clone(),
limits: instance
.read()
@ -238,8 +242,40 @@ impl ChorusUser {
.as_ref()
.map(|info| info.ratelimits.clone()),
settings,
object,
object: None,
gateway,
}
}
/// Sends a request to complete an MFA challenge.
/// # Reference
/// See <https://docs.discord.sex/authentication#verify-mfa>
///
/// If successful, the MFA verification JWT returned is set on the current [ChorusUser] executing the
/// request.
///
/// The JWT token expires after 5 minutes.
pub async fn complete_mfa_challenge(&mut self, mfa_verify_schema: MfaVerifySchema) -> ChorusResult<()> {
let endpoint_url = self.belongs_to.read().unwrap().urls.api.clone() + "/mfa/finish";
let chorus_request = ChorusRequest {
request: Client::new()
.post(endpoint_url)
.header("Authorization", self.token())
.json(&mfa_verify_schema),
limit_type: match self.object.is_some() {
true => LimitType::Global,
false => LimitType::Ip,
},
};
let mfa_token_schema = chorus_request
.deserialize_response::<MfaTokenSchema>(self).await?;
self.mfa_token = Some(MfaToken {
token: mfa_token_schema.token,
expires_at: Utc::now() + Duration::from_secs(60 * 5),
});
Ok(())
}
}

View File

@ -13,7 +13,7 @@ use serde_json::from_str;
use crate::{
errors::{ChorusError, ChorusResult},
instance::ChorusUser,
types::{types::subconfigs::limits::rates::RateLimits, Limit, LimitType, LimitsConfiguration},
types::{types::subconfigs::limits::rates::RateLimits, Limit, LimitType, LimitsConfiguration, MfaRequiredSchema},
};
/// Chorus' request struct. This struct is used to send rate-limited requests to the Spacebar server.
@ -34,13 +34,12 @@ impl ChorusRequest {
/// * [`http::Method::DELETE`]
/// * [`http::Method::PATCH`]
/// * [`http::Method::HEAD`]
#[allow(unused_variables)] // TODO: Add mfa_token to request, once we figure out *how* to do so correctly
#[allow(unused_variables)]
pub fn new(
method: http::Method,
url: &str,
body: Option<String>,
audit_log_reason: Option<&str>,
mfa_token: Option<&str>,
chorus_user: Option<&mut ChorusUser>,
limit_type: LimitType,
) -> ChorusRequest {
@ -266,7 +265,14 @@ impl ChorusRequest {
async fn interpret_error(response: reqwest::Response) -> ChorusError {
match response.status().as_u16() {
401..=403 | 407 => ChorusError::NoPermission,
401 => {
let response = response.text().await.unwrap();
match serde_json::from_str::<MfaRequiredSchema>(&response) {
Ok(response) => ChorusError::MfaRequired { error: response },
Err(_) => ChorusError::NoPermission,
}
}
402..=403 | 407 => ChorusError::NoPermission,
404 => ChorusError::NotFound {
error: response.text().await.unwrap(),
},

View File

@ -0,0 +1,7 @@
use chrono::{DateTime, Utc};
#[derive(Debug, Clone)]
pub struct MfaToken {
pub token: String,
pub expires_at: DateTime<Utc>,
}

View File

@ -26,6 +26,7 @@ pub use user::*;
pub use user_settings::*;
pub use voice_state::*;
pub use webhook::*;
pub use mfa_token::*;
use crate::types::Shared;
#[cfg(feature = "client")]
@ -67,6 +68,7 @@ mod user;
mod user_settings;
mod voice_state;
mod webhook;
mod mfa_token;
#[cfg(feature = "client")]
#[async_trait(?Send)]

View File

@ -35,12 +35,3 @@ pub struct LoginSchema {
pub login_source: Option<String>,
pub gift_code_sku_id: Option<String>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct TotpSchema {
code: String,
ticket: String,
gift_code_sku_id: Option<String>,
login_source: Option<String>,
}

62
src/types/schema/mfa.rs Normal file
View File

@ -0,0 +1,62 @@
use std::fmt::Display;
use serde::{Serialize, Deserialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[serde(rename_all = "snake_case")]
pub struct MfaRequiredSchema {
pub message: String,
pub code: i32,
pub mfa: MfaVerificationSchema,
}
impl Display for MfaRequiredSchema {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("MfaRequired")
.field("message", &self.message)
.field("code", &self.code)
.field("mfa", &self.mfa)
.finish()
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[serde(rename_all = "snake_case")]
pub struct MfaVerificationSchema {
pub ticket: String,
pub methods: Vec<MfaMethod>
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[serde(rename_all = "snake_case")]
pub struct MfaMethod {
#[serde(rename = "type")]
pub kind: MfaType,
#[serde(skip_serializing_if = "Option::is_none")]
pub challenge: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub backup_codes_allowed: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[serde(rename_all = "snake_case")]
pub enum MfaType {
TOTP,
SMS,
Backup,
WebAuthn,
Password,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub struct MfaVerifySchema {
pub ticket: String,
pub mfa_type: MfaType,
pub data: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MfaTokenSchema {
pub token: String,
}

View File

@ -5,6 +5,7 @@
pub use apierror::*;
pub use audit_log::*;
pub use auth::*;
pub use mfa::*;
pub use channel::*;
pub use guild::*;
pub use message::*;
@ -17,6 +18,7 @@ pub use voice_state::*;
mod apierror;
mod audit_log;
mod auth;
mod mfa;
mod channel;
mod guild;
mod message;

View File

@ -85,8 +85,10 @@ async fn test_login_with_token() {
.await
.unwrap();
assert_eq!(
bundle.user.object.read().unwrap().id,
other_user.object.read().unwrap().id
bundle.user.object.as_ref().unwrap()
.read().unwrap()
.id,
other_user.object.unwrap().read().unwrap().id
);
assert_eq!(bundle.user.token, other_user.token);

View File

@ -2,7 +2,11 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
use chorus::types::{self, Channel, GetChannelMessagesSchema, MessageSendSchema, PermissionFlags, PermissionOverwrite, PermissionOverwriteType, PrivateChannelCreateSchema, RelationshipType, Snowflake};
use chorus::types::{
self, Channel, GetChannelMessagesSchema, MessageSendSchema, PermissionFlags,
PermissionOverwrite, PermissionOverwriteType, PrivateChannelCreateSchema, RelationshipType,
Snowflake,
};
mod common;
@ -67,7 +71,7 @@ async fn modify_channel() {
assert_eq!(modified_channel.name, Some(CHANNEL_NAME.to_string()));
let permission_override = PermissionFlags::MANAGE_CHANNELS | PermissionFlags::MANAGE_MESSAGES;
let user_id: types::Snowflake = bundle.user.object.read().unwrap().id;
let user_id: types::Snowflake = bundle.user.object.as_ref().unwrap().read().unwrap().id;
let permission_override = PermissionOverwrite {
id: user_id,
overwrite_type: PermissionOverwriteType::Member,
@ -155,7 +159,13 @@ async fn create_dm() {
let other_user = bundle.create_user("integrationtestuser2").await;
let user = &mut bundle.user;
let private_channel_create_schema = PrivateChannelCreateSchema {
recipients: Some(Vec::from([other_user.object.read().unwrap().id])),
recipients: Some(Vec::from([other_user
.object
.as_ref()
.unwrap()
.read()
.unwrap()
.id])),
access_tokens: None,
nicks: None,
};
@ -175,7 +185,7 @@ async fn create_dm() {
.unwrap()
.id
.clone(),
other_user.object.read().unwrap().id
other_user.object.unwrap().read().unwrap().id
);
assert_eq!(
dm_channel
@ -188,7 +198,7 @@ async fn create_dm() {
.unwrap()
.id
.clone(),
user.object.read().unwrap().id.clone()
user.object.as_ref().unwrap().read().unwrap().id.clone()
);
common::teardown(bundle).await;
}
@ -200,9 +210,9 @@ async fn remove_add_person_from_to_dm() {
let mut bundle = common::setup().await;
let mut other_user = bundle.create_user("integrationtestuser2").await;
let mut third_user = bundle.create_user("integrationtestuser3").await;
let third_user_id = third_user.object.read().unwrap().id;
let other_user_id = other_user.object.read().unwrap().id;
let user_id = bundle.user.object.read().unwrap().id;
let third_user_id = third_user.object.as_ref().unwrap().read().unwrap().id;
let other_user_id = other_user.object.as_ref().unwrap().read().unwrap().id;
let user_id = bundle.user.object.as_ref().unwrap().read().unwrap().id;
let user = &mut bundle.user;
let private_channel_create_schema = PrivateChannelCreateSchema {
recipients: Some(Vec::from([other_user_id, third_user_id])),

View File

@ -47,6 +47,7 @@ impl TestBundle {
ChorusUser {
belongs_to: self.user.belongs_to.clone(),
token: self.user.token.clone(),
mfa_token: None,
limits: self.user.limits.clone(),
settings: self.user.settings.clone(),
object: self.user.object.clone(),

View File

@ -60,7 +60,8 @@ async fn guild_create_ban() {
.await
.unwrap();
other_user.accept_invite(&invite.code, None).await.unwrap();
let other_user_id = other_user.object.read().unwrap().id;
let other_user_id = other_user.object.as_ref().unwrap()
.read().unwrap().id;
Guild::create_ban(
guild.id,
other_user_id,
@ -112,7 +113,9 @@ async fn guild_remove_member() {
.await
.unwrap();
other_user.accept_invite(&invite.code, None).await.unwrap();
let other_user_id = other_user.object.read().unwrap().id;
let other_user_id = other_user.object
.as_ref().unwrap()
.read().unwrap().id;
Guild::remove_member(guild.id, other_user_id, None, &mut bundle.user)
.await
.unwrap();

View File

@ -16,7 +16,8 @@ async fn add_remove_role() -> ChorusResult<()> {
let mut bundle = common::setup().await;
let guild = bundle.guild.read().unwrap().id;
let role = bundle.role.read().unwrap().id;
let member_id = bundle.user.object.read().unwrap().id;
let member_id = bundle.user.object.as_ref().unwrap()
.read().unwrap().id;
GuildMember::add_role(&mut bundle.user, guild, member_id, role).await?;
let member = GuildMember::get(&mut bundle.user, guild, member_id)
.await

View File

@ -106,7 +106,7 @@ async fn search_messages() {
let _arg = Some(&vec_attach);
let message = bundle.user.send_message(message, channel.id).await.unwrap();
let query = MessageSearchQuery {
author_id: Some(Vec::from([bundle.user.object.read().unwrap().id])),
author_id: Some(Vec::from([bundle.user.object.as_ref().unwrap().read().unwrap().id])),
..Default::default()
};
let guild_id = bundle.guild.read().unwrap().id;

View File

@ -16,9 +16,10 @@ async fn test_get_mutual_relationships() {
let mut bundle = common::setup().await;
let mut other_user = bundle.create_user("integrationtestuser2").await;
let user = &mut bundle.user;
let username = user.object.read().unwrap().username.clone();
let discriminator = user.object.read().unwrap().discriminator.clone();
let other_user_id: types::Snowflake = other_user.object.read().unwrap().id;
let username = user.object.as_ref().unwrap().read().unwrap().username.clone();
let discriminator = user.object.as_ref().unwrap().read().unwrap().discriminator.clone();
let other_user_id: types::Snowflake = other_user.object.as_ref().unwrap().read().unwrap().id;
let friend_request_schema = types::FriendRequestSendSchema {
username,
discriminator: Some(discriminator),
@ -38,8 +39,8 @@ async fn test_get_relationships() {
let mut bundle = common::setup().await;
let mut other_user = bundle.create_user("integrationtestuser2").await;
let user = &mut bundle.user;
let username = user.object.read().unwrap().username.clone();
let discriminator = user.object.read().unwrap().discriminator.clone();
let username = user.object.as_ref().unwrap().read().unwrap().username.clone();
let discriminator = user.object.as_ref().unwrap().read().unwrap().discriminator.clone();
let friend_request_schema = types::FriendRequestSendSchema {
username,
discriminator: Some(discriminator),
@ -51,7 +52,7 @@ async fn test_get_relationships() {
let relationships = user.get_relationships().await.unwrap();
assert_eq!(
relationships.get(0).unwrap().id,
other_user.object.read().unwrap().id
other_user.object.unwrap().read().unwrap().id
);
common::teardown(bundle).await
}
@ -62,8 +63,8 @@ async fn test_modify_relationship_friends() {
let mut bundle = common::setup().await;
let mut other_user = bundle.create_user("integrationtestuser2").await;
let user = &mut bundle.user;
let user_id: types::Snowflake = user.object.read().unwrap().id;
let other_user_id: types::Snowflake = other_user.object.read().unwrap().id;
let user_id: types::Snowflake = user.object.as_ref().unwrap().read().unwrap().id;
let other_user_id: types::Snowflake = other_user.object.as_ref().unwrap().read().unwrap().id;
other_user
.modify_user_relationship(user_id, types::RelationshipType::Friends)
@ -72,7 +73,7 @@ async fn test_modify_relationship_friends() {
let relationships = user.get_relationships().await.unwrap();
assert_eq!(
relationships.get(0).unwrap().id,
other_user.object.read().unwrap().id
other_user.object.as_ref().unwrap().read().unwrap().id
);
assert_eq!(
relationships.get(0).unwrap().relationship_type,
@ -81,7 +82,7 @@ async fn test_modify_relationship_friends() {
let relationships = other_user.get_relationships().await.unwrap();
assert_eq!(
relationships.get(0).unwrap().id,
user.object.read().unwrap().id
user.object.as_ref().unwrap().read().unwrap().id
);
assert_eq!(
relationships.get(0).unwrap().relationship_type,
@ -114,7 +115,7 @@ async fn test_modify_relationship_block() {
let mut bundle = common::setup().await;
let mut other_user = bundle.create_user("integrationtestuser2").await;
let user = &mut bundle.user;
let user_id: types::Snowflake = user.object.read().unwrap().id;
let user_id: types::Snowflake = user.object.as_ref().unwrap().read().unwrap().id;
other_user
.modify_user_relationship(user_id, types::RelationshipType::Blocked)
@ -125,7 +126,7 @@ async fn test_modify_relationship_block() {
let relationships = other_user.get_relationships().await.unwrap();
assert_eq!(
relationships.get(0).unwrap().id,
user.object.read().unwrap().id
user.object.as_ref().unwrap().read().unwrap().id
);
assert_eq!(
relationships.get(0).unwrap().relationship_type,