use crate::{Client, RoboatError};
use reqwest::header;
use serde::{Deserialize, Serialize};
mod request_types;
const FRIENDS_LIST_API: &str = "https://friends.roblox.com/v1/users/{user_id}/friends";
const FRIEND_REQUESTS_API: &str = "https://friends.roblox.com/v1/my/friends/requests";
const PENDING_FRIEND_REQUESTS_API: &str =
"https://friends.roblox.com/v1/user/friend-requests/count";
const ACCEPT_FRIEND_REQUEST_API: &str =
"https://friends.roblox.com/v1/users/{requester_id}/accept-friend-request";
const DECLINE_FRIEND_REQUEST_API: &str =
"https://friends.roblox.com/v1/users/{requester_id}/decline-friend-request";
const SEND_FRIEND_REQUEST_API: &str =
"https://friends.roblox.com/v1/users/{target_id}/request-friendship";
const UNFRIEND_API: &str = "https://friends.roblox.com/v1/users/{target_id}/unfriend";
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
#[allow(missing_docs)]
pub struct FriendRequestsResponse {
pub previous_page_cursor: Option<String>,
pub next_page_cursor: Option<String>,
pub data: Vec<request_types::RequestResponseData>,
}
impl IntoIterator for FriendRequestsResponse {
type Item = request_types::RequestResponseData;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.data.into_iter()
}
}
impl Client {
pub async fn friends_list(
&self,
user_id: u64,
) -> Result<Vec<request_types::FriendUserInformation>, RoboatError> {
let formatted_url = FRIENDS_LIST_API.replace("{user_id}", &user_id.to_string());
let request_result = self.reqwest_client.get(formatted_url).send().await;
let response = Self::validate_request_result(request_result).await?;
let friends = Self::parse_to_raw::<request_types::FriendsListResponse>(response).await?;
Ok(friends.data)
}
pub async fn friend_requests(
&self,
cursor: Option<String>,
) -> Result<(FriendRequestsResponse, Option<String>), RoboatError> {
let cookie = self.cookie_string()?;
let mut formatted_url = format!("{}?limit={}", FRIEND_REQUESTS_API, 10);
if let Some(cursor) = cursor {
formatted_url = format!("{}&cursor={}", formatted_url, cursor)
}
let request_result = self
.reqwest_client
.get(formatted_url)
.header(header::COOKIE, cookie)
.send()
.await;
let response = Self::validate_request_result(request_result).await?;
let raw = Self::parse_to_raw::<FriendRequestsResponse>(response).await?;
let next_page_cursor = raw.next_page_cursor.clone();
Ok((raw, next_page_cursor))
}
pub async fn pending_friend_requests(&self) -> Result<u64, RoboatError> {
let cookie = self.cookie_string()?;
let formatted_url = PENDING_FRIEND_REQUESTS_API;
let request_result = self
.reqwest_client
.get(formatted_url)
.header(header::COOKIE, cookie)
.send()
.await;
let response = Self::validate_request_result(request_result).await?;
let raw =
Self::parse_to_raw::<request_types::PendingFriendRequestsResponse>(response).await?;
Ok(raw.count)
}
pub async fn accept_friend_request(&self, requester_id: u64) -> Result<(), RoboatError> {
match self.accept_friend_request_internal(requester_id).await {
Ok(x) => Ok(x),
Err(e) => match e {
RoboatError::InvalidXcsrf(new_xcsrf) => {
self.set_xcsrf(new_xcsrf).await;
self.accept_friend_request_internal(requester_id).await
}
_ => Err(e),
},
}
}
pub async fn decline_friend_request(&self, requester_id: u64) -> Result<(), RoboatError> {
match self.decline_friend_request_internal(requester_id).await {
Ok(x) => Ok(x),
Err(e) => match e {
RoboatError::InvalidXcsrf(new_xcsrf) => {
self.set_xcsrf(new_xcsrf).await;
self.decline_friend_request_internal(requester_id).await
}
_ => Err(e),
},
}
}
pub async fn send_friend_request(&self, target_id: u64) -> Result<(), RoboatError> {
match self.send_friend_request_internal(target_id).await {
Ok(_) => Ok(()),
Err(e) => match e {
RoboatError::InvalidXcsrf(new_xcsrf) => {
self.set_xcsrf(new_xcsrf).await;
self.send_friend_request_internal(target_id).await
}
_ => Err(e),
},
}
}
pub async fn unfriend(&self, target_id: u64) -> Result<(), RoboatError> {
match self.unfriend_internal(target_id).await {
Ok(_) => Ok(()),
Err(e) => match e {
RoboatError::InvalidXcsrf(new_xcsrf) => {
self.set_xcsrf(new_xcsrf).await;
self.unfriend_internal(target_id).await
}
_ => Err(e),
},
}
}
}
mod internal {
use reqwest::header;
use serde_json::json;
use crate::{Client, RoboatError, XCSRF_HEADER};
impl Client {
pub(super) async fn accept_friend_request_internal(
&self,
requester_id: u64,
) -> Result<(), RoboatError> {
let formatted_url = super::ACCEPT_FRIEND_REQUEST_API
.replace("{requester_id}", &requester_id.to_string());
let cookie = self.cookie_string()?;
let xcsrf = self.xcsrf().await;
let request_result = self
.reqwest_client
.post(formatted_url)
.header(header::COOKIE, cookie)
.header(XCSRF_HEADER, xcsrf)
.send()
.await;
let _ = Self::validate_request_result(request_result).await?;
Ok(())
}
pub(super) async fn decline_friend_request_internal(
&self,
requester_id: u64,
) -> Result<(), RoboatError> {
let formatted_url = super::DECLINE_FRIEND_REQUEST_API
.replace("{requester_id}", &requester_id.to_string());
let cookie = self.cookie_string()?;
let xcsrf = self.xcsrf().await;
let request_result = self
.reqwest_client
.post(formatted_url)
.header(header::COOKIE, cookie)
.header(XCSRF_HEADER, xcsrf)
.send()
.await;
let _ = Self::validate_request_result(request_result).await?;
Ok(())
}
pub(super) async fn send_friend_request_internal(
&self,
target_id: u64,
) -> Result<(), RoboatError> {
let formatted_url =
super::SEND_FRIEND_REQUEST_API.replace("{target_id}", &target_id.to_string());
let cookie = self.cookie_string()?;
let xcsrf = self.xcsrf().await;
let body = json!({
"friendshipOriginSourceType": 0
});
let request_result = self
.reqwest_client
.post(formatted_url)
.header(header::COOKIE, cookie)
.header(XCSRF_HEADER, xcsrf)
.json(&body)
.send()
.await;
let _ = Self::validate_request_result(request_result).await?;
Ok(())
}
pub(super) async fn unfriend_internal(&self, target_id: u64) -> Result<(), RoboatError> {
let formatted_url = super::UNFRIEND_API.replace("{target_id}", &target_id.to_string());
let cookie = self.cookie_string()?;
let xcsrf = self.xcsrf().await;
let request_result = self
.reqwest_client
.post(formatted_url)
.header(header::COOKIE, cookie)
.header(XCSRF_HEADER, xcsrf)
.send()
.await;
let _ = Self::validate_request_result(request_result).await?;
Ok(())
}
}
}