diff --git a/src/api/users/users.rs b/src/api/users/users.rs index 15f0aa6..9357615 100644 --- a/src/api/users/users.rs +++ b/src/api/users/users.rs @@ -11,7 +11,10 @@ use crate::{ errors::{ChorusError, ChorusResult}, instance::{ChorusUser, Instance}, ratelimiter::ChorusRequest, - types::{LimitType, PublicUser, Snowflake, User, UserModifySchema, UserProfile, UserSettings}, + types::{ + LimitType, PublicUser, Snowflake, User, UserModifyProfileSchema, UserModifySchema, + UserProfile, UserProfileMetadata, UserSettings, + }, }; impl ChorusUser { @@ -133,6 +136,22 @@ impl ChorusUser { pub async fn get_user_profile(&mut self, id: Snowflake) -> ChorusResult { User::get_profile(self, id).await } + + /// Modifies the current user's profile. + /// + /// Returns the updated [UserProfileMetadata]. + /// + /// # Notes + /// This function is a wrapper around [`User::modify_profile`]. + /// + /// # Reference + /// See + pub async fn modify_profile( + &mut self, + schema: UserModifyProfileSchema, + ) -> ChorusResult { + User::modify_profile(self, schema).await + } } impl User { @@ -247,4 +266,28 @@ impl User { .deserialize_response::(user) .await } + + /// Modifies the current user's profile. + /// + /// Returns the updated [UserProfileMetadata]. + /// + /// # Reference + /// See + pub async fn modify_profile( + user: &mut ChorusUser, + schema: UserModifyProfileSchema, + ) -> ChorusResult { + let url_api = user.belongs_to.read().unwrap().urls.api.clone(); + let request: reqwest::RequestBuilder = Client::new() + .patch(format!("{}/users/@me/profile", url_api)) + .header("Authorization", user.token()) + .json(&schema); + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::Global, + }; + chorus_request + .deserialize_response::(user) + .await + } } diff --git a/src/types/schema/user.rs b/src/types/schema/user.rs index e2600a4..c7f89ba 100644 --- a/src/types/schema/user.rs +++ b/src/types/schema/user.rs @@ -7,7 +7,7 @@ use std::collections::HashMap; use chrono::NaiveDate; use serde::{Deserialize, Serialize}; -use crate::types::Snowflake; +use crate::types::{Snowflake, ThemeColors}; #[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] #[serde(rename_all = "snake_case")] @@ -31,7 +31,7 @@ pub struct UserModifySchema { // TODO: Add a CDN data type pub avatar: Option, /// Note: This is not yet implemented on Spacebar - pub avatar_decoration_id: Option, + pub avatar_decoration_id: Option, /// Note: This is not yet implemented on Spacebar pub avatar_decoration_sku_id: Option, /// The user's email address; if changing from a verified email, email_token must be provided @@ -106,3 +106,44 @@ pub struct PrivateChannelCreateSchema { pub access_tokens: Option>, pub nicks: Option>, } + +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// A schema used to modify the current user's profile. +/// +/// Similar to [crate::types::UserProfileMetadata] +/// +/// See +pub struct UserModifyProfileSchema { + // Note: one of these causes a 500 if it is sent + #[serde(skip_serializing_if = "Option::is_none")] + /// The user's new pronouns (max 40 characters) + pub pronouns: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + /// The user's new bio (max 190 characters) + pub bio: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + // TODO: Add banner -- do we have an image data struct + /// The user's new accent color encoded as an i32 representation of a hex color code + pub accent_color: Option, + + // Note: without the skip serializing this currently (2024/07/28) causes a 500! + // + // Which in turns locks the user's account, requiring phone number verification + #[serde(skip_serializing_if = "Option::is_none")] + /// The user's new [ThemeColors] + pub theme_colors: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + /// The user's new profile popup animation particle type + pub popout_animation_particle_type: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + /// The user's new profile emoji id + pub emoji_id: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + /// The user's new profile ffect id + pub profile_effect_id: Option, +}