diff --git a/src/helix/client/client_ext.rs b/src/helix/client/client_ext.rs index bf44511851..9fb5555310 100644 --- a/src/helix/client/client_ext.rs +++ b/src/helix/client/client_ext.rs @@ -1220,6 +1220,22 @@ impl<'client, C: crate::HttpClient + Sync + 'client> HelixClient<'client, C> { .try_flatten_unordered(None) } + /// Update the user's description + /// + /// The user ID in the OAuth token identifies the user whose information you want to update. + pub async fn update_user_description<'b, T>( + &'client self, + description: impl Into> + Send, + token: &T, + ) -> Result> + where + T: TwitchToken + Send + Sync + ?Sized, + { + let req = helix::users::UpdateUserRequest::description(description); + + Ok(self.req_put(req, helix::EmptyBody, token).await?.data) + } + /// Retrieves the active shared chat session for a channel /// /// [`None`] is returned if no shared chat session is active. diff --git a/src/helix/endpoints/users/mod.rs b/src/helix/endpoints/users/mod.rs index 13b0fdc789..f9c926c0e3 100644 --- a/src/helix/endpoints/users/mod.rs +++ b/src/helix/endpoints/users/mod.rs @@ -23,12 +23,12 @@ //! //! //! -//!
Users 🟡 4/8 +//!
Users 🟡 5/8 //! //! | Endpoint | Helper | Module | //! |---|---|---| //! | [Get Users](https://dev.twitch.tv/docs/api/reference#get-users) | [`HelixClient::get_user_from_id`](crate::helix::HelixClient::get_user_from_id), [`HelixClient::get_user_from_login`](crate::helix::HelixClient::get_user_from_login), [`HelixClient::get_users_from_ids`](crate::helix::HelixClient::get_users_from_ids) | [`get_users`] | -//! | [Update User](https://dev.twitch.tv/docs/api/reference#update-user) | - | - | +//! | [Update User](https://dev.twitch.tv/docs/api/reference#update-user) | [`HelixClient::update_user_description`](crate::helix::HelixClient::update_user_description) | [`update_user`] | //! | [Get User Block List](https://dev.twitch.tv/docs/api/reference#get-user-block-list) | - | [`get_user_block_list`] | //! | [Block User](https://dev.twitch.tv/docs/api/reference#block-user) | [`HelixClient::block_user`](crate::helix::HelixClient::block_user) | [`block_user`] | //! | [Unblock User](https://dev.twitch.tv/docs/api/reference#unblock-user) | [`HelixClient::unblock_user`](crate::helix::HelixClient::unblock_user) | [`unblock_user`] | @@ -51,6 +51,7 @@ pub mod get_user_block_list; pub mod get_users; pub mod get_users_follows; pub mod unblock_user; +pub mod update_user; #[doc(inline)] pub use block_user::{BlockUser, BlockUserRequest}; @@ -62,3 +63,5 @@ pub use get_users::{GetUsersRequest, User}; pub use get_users_follows::{FollowRelationship, GetUsersFollowsRequest, UsersFollows}; #[doc(inline)] pub use unblock_user::{UnblockUser, UnblockUserRequest}; +#[doc(inline)] +pub use update_user::UpdateUserRequest; diff --git a/src/helix/endpoints/users/update_user.rs b/src/helix/endpoints/users/update_user.rs new file mode 100644 index 0000000000..d1c0e9c29b --- /dev/null +++ b/src/helix/endpoints/users/update_user.rs @@ -0,0 +1,188 @@ +//! Updates the specified user’s information. +//! +//! [`update-user`](https://dev.twitch.tv/docs/api/reference/#update-user) +//! +//! The user ID in the OAuth token identifies the user whose information you want to update. +//! +//! # Accessing the endpoint +//! +//! ## Request: [UpdateUserRequest] +//! +//! To use this endpoint, construct an [`UpdateUserRequest`] with the [`UpdateUserRequest::description()`] method. +//! +//! ```rust +//! use twitch_api::helix::users::update_user; +//! let mut request = +//! update_user::UpdateUserRequest::description("my description"); +//! ``` +//! +//! ## Response: [User] +//! +//! +//! Send the request to receive the response with [`HelixClient::req_patch()`](helix::HelixClient::req_patch). +//! +//! +//! ```rust, no_run +//! use twitch_api::helix::{self, users::update_user}; +//! # use twitch_api::client; +//! # #[tokio::main] +//! # async fn main() -> Result<(), Box> { +//! # let client: helix::HelixClient<'static, client::DummyHttpClient> = helix::HelixClient::default(); +//! # let token = twitch_oauth2::AccessToken::new("validtoken".to_string()); +//! # let token = twitch_oauth2::UserToken::from_existing(&client, token, None, None).await?; +//! let mut request = update_user::UpdateUserRequest::description("my description"); +//! let body = helix::EmptyBody; +//! let response: helix::users::User = client.req_put(request, body, &token).await?.data; +//! # Ok(()) +//! # } +//! ``` +//! +//! You can also get the [`http::Request`] with [`request.create_request(&token, &client_id)`](helix::RequestPost::create_request) +//! and parse the [`http::Response`] with [`UpdateUserRequest::parse_response(None, &request.get_uri(), response)`](UpdateUserRequest::parse_response) +use super::*; +use helix::RequestPut; + +/// Query Parameters for [Update User](super::update_user) +/// +/// [`update-user`](https://dev.twitch.tv/docs/api/reference#update-user) +#[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] +#[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] +#[must_use] +#[non_exhaustive] +pub struct UpdateUserRequest<'a> { + /// The string to update the channel’s description to. The description is limited to a maximum of 300 characters. + /// + /// To remove the description, specify this parameter but don’t set it’s value (specify an empty string). + #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] + #[cfg_attr(feature = "deser_borrow", serde(borrow = "'a"))] + pub description: Option>, +} + +impl<'a> UpdateUserRequest<'a> { + /// Update nothing (returns the current user) + pub fn empty() -> Self { Self { description: None } } + + /// Update the description of the current user + pub fn description(description: impl Into>) -> Self { + Self { + description: Some(description.into()), + } + } +} + +impl Request for UpdateUserRequest<'_> { + type Response = User; + + const PATH: &'static str = "users"; + #[cfg(feature = "twitch_oauth2")] + const SCOPE: twitch_oauth2::Validator = + twitch_oauth2::validator![twitch_oauth2::Scope::UserEdit]; +} + +impl RequestPut for UpdateUserRequest<'_> { + type Body = helix::EmptyBody; + + fn parse_inner_response( + request: Option, + uri: &http::Uri, + response: &str, + status: http::StatusCode, + ) -> Result, helix::HelixRequestPutError> + where + Self: Sized, + { + helix::parse_single_return(request, uri, response, status) + } +} + +#[cfg(test)] +#[test] +fn test_request() { + let req = UpdateUserRequest::description("my description"); + + let body = helix::EmptyBody; + + dbg!(req.create_request(body, "token", "clientid").unwrap()); + + // From twitch docs (slightly modified to include a space) + let data = br#" + { + "data":[{ + "id": "44322889", + "login": "dallas", + "display_name": "dallas", + "type": "staff", + "broadcaster_type": "affiliate", + "description": "my description", + "profile_image_url": "https://static-cdn.jtvnw.net/jtv_user_pictures/4d1f36cbf1f0072d-profile_image-300x300.png", + "offline_image_url": "https://static-cdn.jtvnw.net/jtv_user_pictures/dallas-channel_offline_image-2e82c1df2a464df7-1920x1080.jpeg", + "view_count": 6995, + "email": "not-real@email.com", + "created_at": "2013-06-03T19:12:02.580593Z" + }] + } + "#.to_vec(); + + let http_response = http::Response::builder().status(200).body(data).unwrap(); + + let uri = req.get_uri().unwrap(); + assert_eq!( + uri.to_string(), + "https://api.twitch.tv/helix/users?description=my+description" + ); + + let res = UpdateUserRequest::parse_response(Some(req), &uri, http_response) + .unwrap() + .data; + + assert_eq!(res.id.as_str(), "44322889"); + assert_eq!(res.type_, Some(types::UserType::Staff)); + assert_eq!( + res.broadcaster_type, + Some(types::BroadcasterType::Affiliate) + ); + assert_eq!(res.login.as_str(), "dallas"); + assert_eq!(res.description.unwrap(), "my description"); +} + +#[cfg(test)] +#[test] +fn test_request_empty() { + let req = UpdateUserRequest::empty(); + + let body = helix::EmptyBody; + + dbg!(req.create_request(body, "token", "clientid").unwrap()); + + let data = br#" + { + "data": [ + { + "broadcaster_type": "", + "created_at": "2016-07-14T16:13:40Z", + "description": "hi", + "display_name": "nerixyz", + "id": "129546453", + "login": "nerixyz", + "offline_image_url": "", + "profile_image_url": "https://static-cdn.jtvnw.net/jtv_user_pictures/e065218b-49df-459d-afd3-c6557870f551-profile_image-300x300.png", + "type": "", + "view_count": 0 + } + ] + } + "#.to_vec(); + + let http_response = http::Response::builder().status(200).body(data).unwrap(); + + let uri = req.get_uri().unwrap(); + assert_eq!(uri.to_string(), "https://api.twitch.tv/helix/users?"); + + let res = UpdateUserRequest::parse_response(Some(req), &uri, http_response) + .unwrap() + .data; + + assert_eq!(res.id.as_str(), "129546453"); + assert_eq!(res.type_, Some(types::UserType::None)); + assert_eq!(res.broadcaster_type, Some(types::BroadcasterType::None)); +} diff --git a/src/helix/mod.rs b/src/helix/mod.rs index d06ab29f93..ecc59cd6e1 100644 --- a/src/helix/mod.rs +++ b/src/helix/mod.rs @@ -351,12 +351,12 @@ //! //!
//! -//!
Users 🟡 4/8 +//!
Users 🟡 5/8 //! //! | Endpoint | Helper | Module | //! |---|---|---| //! | [Get Users](https://dev.twitch.tv/docs/api/reference#get-users) | [`HelixClient::get_user_from_id`], [`HelixClient::get_user_from_login`], [`HelixClient::get_users_from_ids`] | [`users::get_users`] | -//! | [Update User](https://dev.twitch.tv/docs/api/reference#update-user) | - | - | +//! | [Update User](https://dev.twitch.tv/docs/api/reference#update-user) | [`HelixClient::update_user_description`] | [`users::update_user`] | //! | [Get User Block List](https://dev.twitch.tv/docs/api/reference#get-user-block-list) | - | [`users::get_user_block_list`] | //! | [Block User](https://dev.twitch.tv/docs/api/reference#block-user) | [`HelixClient::block_user`] | [`users::block_user`] | //! | [Unblock User](https://dev.twitch.tv/docs/api/reference#unblock-user) | [`HelixClient::unblock_user`] | [`users::unblock_user`] | diff --git a/xtask/src/collect_endpoints/helix.rs b/xtask/src/collect_endpoints/helix.rs index 07bb1fc24f..b63888f74b 100644 --- a/xtask/src/collect_endpoints/helix.rs +++ b/xtask/src/collect_endpoints/helix.rs @@ -262,6 +262,7 @@ pub fn distance(src: &str, tar: &str) -> usize { "from_id", "from_logins", "from_login", + "description", ]; fn remove_ignored_phrases(s: &str, ignore_phrases: &[&str]) -> String {