diff --git a/src/api/users/users.rs b/src/api/users/users.rs index 92fbb6e0..1de9edc3 100644 --- a/src/api/users/users.rs +++ b/src/api/users/users.rs @@ -2,7 +2,10 @@ // 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 std::sync::{Arc, RwLock}; +use std::{ + collections::HashMap, + sync::{Arc, RwLock}, +}; use reqwest::Client; use serde_json::to_string; @@ -14,9 +17,9 @@ use crate::{ types::{ CreateUserHarvestSchema, DeleteDisableUserSchema, GetPomeloEligibilityReturn, GetPomeloSuggestionsReturn, GetRecentMentionsSchema, GetUserProfileSchema, Harvest, - HarvestBackendType, LimitType, PublicUser, Snowflake, User, UserModifyProfileSchema, - UserModifySchema, UserProfile, UserProfileMetadata, UserSettings, - VerifyUserEmailChangeResponse, VerifyUserEmailChangeSchema, + HarvestBackendType, LimitType, ModifyUserNoteSchema, PublicUser, Snowflake, User, + UserModifyProfileSchema, UserModifySchema, UserNote, UserProfile, UserProfileMetadata, + UserSettings, VerifyUserEmailChangeResponse, VerifyUserEmailChangeSchema, }, }; @@ -224,11 +227,12 @@ impl ChorusUser { /// Verifies a code sent to change the current user's email. /// - /// Should be the follow-up to [Self::initiate_email_change] - /// /// This endpoint returns a token which can be used with [Self::modify] /// to set a new email address (email_token). /// + /// # Notes + /// Should be the follow-up to [Self::initiate_email_change] + /// /// As of 2024/08/08, Spacebar does not yet implement this endpoint. // FIXME: Does this mean PUT users/@me/email is different? /// @@ -256,8 +260,7 @@ impl ChorusUser { /// Returns a suggested unique username based on the current user's username. /// - /// Note: - /// + /// # Notes: /// "This endpoint is used during the pomelo migration flow. /// /// The user must be in the rollout to use this endpoint." @@ -267,6 +270,7 @@ impl ChorusUser { /// /// As of 2024/08/08, Spacebar does not yet implement this endpoint. /// + /// # Reference /// See pub async fn get_pomelo_suggestions(&mut self) -> ChorusResult { let request = Client::new() @@ -290,8 +294,10 @@ impl ChorusUser { /// /// Returns whether the username is not taken yet. /// + /// # Notes /// As of 2024/08/08, Spacebar does not yet implement this endpoint. /// + /// # Reference /// See pub async fn get_pomelo_eligibility(&mut self, username: &String) -> ChorusResult { let request = Client::new() @@ -321,8 +327,7 @@ impl ChorusUser { /// Updates [Self::object] to an updated representation returned by the server. // FIXME: Is this appropriate behaviour? /// - /// Note: - /// + /// # Notes /// "This endpoint is used during the pomelo migration flow. /// /// The user must be in the rollout to use this endpoint." @@ -332,6 +337,7 @@ impl ChorusUser { // /// As of 2024/08/08, Spacebar does not yet implement this endpoint. /// + /// # Reference /// See pub async fn create_pomelo_migration(&mut self, username: &String) -> ChorusResult<()> { let request = Client::new() @@ -363,8 +369,10 @@ impl ChorusUser { /// Fetches a list of [Message](crate::types::Message)s that the current user has been /// mentioned in during the last 7 days. /// + /// # Notes /// As of 2024/08/09, Spacebar does not yet implement this endpoint. /// + /// # Reference /// See pub async fn get_recent_mentions( &mut self, @@ -390,10 +398,12 @@ impl ChorusUser { /// Acknowledges a message the current user has been mentioned in. /// - /// Fires a RecentMentionDelete gateway event. (Note: yet to be implemented in chorus, see [#545](https://github.com/polyphony-chat/chorus/issues/545)) + /// Fires a `RecentMentionDelete` gateway event. (Note: yet to be implemented in chorus, see [#545](https://github.com/polyphony-chat/chorus/issues/545)) /// + /// # Notes /// As of 2024/08/09, Spacebar does not yet implement this endpoint. /// + /// # Reference /// See pub async fn delete_recent_mention(&mut self, message_id: Snowflake) -> ChorusResult<()> { let request = Client::new() @@ -416,8 +426,10 @@ impl ChorusUser { /// /// To create a new [Harvest], see [Self::create_harvest]. /// + /// # Notes /// As of 2024/08/09, Spacebar does not yet implement this endpoint. (Or data harvesting) /// + /// # Reference /// See pub async fn get_harvest(&mut self) -> ChorusResult> { let request = Client::new() @@ -469,6 +481,7 @@ impl ChorusUser { /// Creates a personal data harvest request ([Harvest]) for the current user. /// + /// # Notes /// To fetch the latest existing harvest, see [Self::get_harvest]. /// /// Invalid options in the backends array are ignored. @@ -477,6 +490,7 @@ impl ChorusUser { /// /// As of 2024/08/09, Spacebar does not yet implement this endpoint. (Or data harvesting) /// + /// # Reference /// See pub async fn create_harvest( &mut self, @@ -505,6 +519,57 @@ impl ChorusUser { chorus_request.deserialize_response(self).await } + + /// Returns a mapping of user IDs ([Snowflake]s) to notes ([String]s) for the current user. + /// + /// # Reference + /// See + pub async fn get_user_notes(&mut self) -> ChorusResult> { + let request = Client::new() + .get(format!( + "{}/users/@me/notes", + self.belongs_to.read().unwrap().urls.api, + )) + .header("Authorization", self.token()); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request.deserialize_response(self).await + } + + /// Fetches the note ([UserNote]) for the given user. + /// + /// If the current user has no note for the target, this endpoint + /// returns `Err(NotFound { error: "{\"message\": \"Unknown User\", \"code\": 10013}" })` + /// + /// # Notes + /// This function is a wrapper around [`User::get_note`]. + /// + /// # Reference + /// See + pub async fn get_user_note(&mut self, target_user_id: Snowflake) -> ChorusResult { + User::get_note(self, target_user_id).await + } + + /// Sets the note for the given user. + /// + /// Fires a `UserNoteUpdate` gateway event. (Note: yet to be implemented in chorus, see [#546](https://github.com/polyphony-chat/chorus/issues/546)) + /// + /// # Notes + /// This function is a wrapper around [`User::set_note`]. + /// + /// # Reference + /// See + pub async fn set_user_note( + &mut self, + target_user_id: Snowflake, + note: Option, + ) -> ChorusResult<()> { + User::set_note(self, target_user_id, note).await + } } impl User { @@ -659,4 +724,61 @@ impl User { .deserialize_response::(user) .await } + + /// Fetches the note ([UserNote]) for the given user. + /// + /// If the current user has no note for the target, this endpoint + /// returns `Err(NotFound { error: "{\"message\": \"Unknown User\", \"code\": 10013}" })` + /// + /// # Reference + /// See + pub async fn get_note( + user: &mut ChorusUser, + target_user_id: Snowflake, + ) -> ChorusResult { + let request = Client::new() + .get(format!( + "{}/users/@me/notes/{}", + user.belongs_to.read().unwrap().urls.api, + target_user_id + )) + .header("Authorization", user.token()); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request.deserialize_response(user).await + } + + /// Sets the note for the given user. + /// + /// Fires a `UserNoteUpdate` gateway event. (Note: yet to be implemented in chorus, see [#546](https://github.com/polyphony-chat/chorus/issues/546)) + /// + /// # Reference + /// See + pub async fn set_note( + user: &mut ChorusUser, + target_user_id: Snowflake, + note: Option, + ) -> ChorusResult<()> { + let schema = ModifyUserNoteSchema { note }; + + let request = Client::new() + .put(format!( + "{}/users/@me/notes/{}", + user.belongs_to.read().unwrap().urls.api, + target_user_id + )) + .header("Authorization", user.token()) + .json(&schema); + + let chorus_request = ChorusRequest { + request, + limit_type: LimitType::default(), + }; + + chorus_request.handle_request_as_result(user).await + } } diff --git a/src/types/entities/user.rs b/src/types/entities/user.rs index caf497d1..09ed96b7 100644 --- a/src/types/entities/user.rs +++ b/src/types/entities/user.rs @@ -765,3 +765,22 @@ pub struct MutualGuild { /// The user's nickname in the guild, if any pub nick: Option, } + +/// Structure which is returned by the [crate::instance::ChorusUser::get_user_note] endpoint. +/// +/// Note that [crate::instance::ChorusUser::get_user_notes] endpoint +/// returns a completely different structure; +// Specualation: this is probably how Discord stores notes internally +/// +/// # Reference +/// See +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] +pub struct UserNote { + /// Actual note contents; max 256 characters + pub note: String, + /// The ID of the user the note is on + pub note_user_id: Snowflake, + /// The ID of the user who created the note (always the current user) + pub user_id: Snowflake, +} diff --git a/src/types/schema/user.rs b/src/types/schema/user.rs index bc641d6a..cc6e36bf 100644 --- a/src/types/schema/user.rs +++ b/src/types/schema/user.rs @@ -267,3 +267,11 @@ pub struct GetRecentMentionsSchema { pub(crate) struct CreateUserHarvestSchema { pub backends: Option>, } + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// Internal type for the [crate::instance::ChorusUser::set_user_note] endpoint. +/// +/// See +pub(crate) struct ModifyUserNoteSchema { + pub note: Option, +}