Skip to content

Commit

Permalink
Merge branch 'main' into dev-main
Browse files Browse the repository at this point in the history
  • Loading branch information
fekie authored May 14, 2024
2 parents f7c5e02 + 84197c6 commit 283c903
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 7 deletions.
29 changes: 22 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<img align="right" src="images/icon.png" height="150px" alt="roboat logo">

# roboat

A high performance interface for the Roblox API.

This library is designed to be high-performance capable, meaning that it supports proxies
Expand All @@ -15,7 +16,8 @@ and is capable of making requests in parallel.
Note that this crate is still in early development and updates may be breaking until the first major version is released.

# Documentation
Extensive documentation is used throughout this crate.

Extensive documentation is used throughout this crate.
All public methods in this crate are documented and have at least one corresponding example.

Documentation can be found [here](https://docs.rs/roboat/).
Expand Down Expand Up @@ -68,19 +70,23 @@ Documentation can be found [here](https://docs.rs/roboat/).
- Fetch Username - [`Client::username`](https://docs.rs/roboat/latest/roboat/struct.Client.html#method.username)
- Fetch Display Name - [`Client::display_name`](https://docs.rs/roboat/latest/roboat/struct.Client.html#method.display_name)
- User Search - [`Client::user_search`](https://docs.rs/roboat/latest/roboat/struct.Client.html#method.user_search)
- Username User Search - [`Client::username_user_search`](https://docs.rs/roboat/latest/roboat/struct.Client.html#method.username_user_search)
- Fetch User Details - [`Client::user_details`](https://docs.rs/roboat/latest/roboat/struct.Client.html#method.user_details)
* UNDER CONSTRUCTION
- Upload Classic Clothing to Group - [`Client::upload_classic_clothing_to_group`](https://docs.rs/roboat/latest/roboat/struct.Client.html#method.upload_classic_clothing_to_group)

# Setup

You can add the latest version of roboat to your project by running:

```bash
cargo add roboat
```

# Quick Start Examples

## Example 1 - Purchase Free UGC Limited

This code snippet allows you to purchase a free ugc limited.

It can be modified to purchase a non-free ugc limited by changing the price.
Expand Down Expand Up @@ -141,14 +147,14 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let robux = client.robux().await?;
let user_id = client.user_id().await?;
let username = client.username().await?;
let display_name = client.display_name().await?;
let display_name = client.display_name().await?;

println!("Robux: {}", robux);
println!("User ID: {}", user_id);
println!("Username: {}", username);
println!("Display Name: {}", display_name);

Ok(())
Ok(())
}
```

Expand All @@ -173,9 +179,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {

let (resellers, _) = client.resellers(item_id, limit, cursor).await?;

println!("Lowest Price for Valkyrie Helm: {}", resellers[0].price);
println!("Lowest Price for Valkyrie Helm: {}", resellers[0].price);

Ok(())
Ok(())
}
```

Expand Down Expand Up @@ -207,22 +213,31 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Creator Name: {}", creator_name);
println!("Price: {}", price);

Ok(())
Ok(())
}
```

# More Examples

More examples can be found in the [examples](examples) directory.

# Related Crates

This crate is a sister crate of [roli](https://crates.io/crates/roli), an API wrapper for [Rolimons.com](https://www.rolimons.com/).

# Requesting

Don't see an endpoint you need covered? Request it in an issue or join the [Discord Server](https://discord.com/invite/QmBEgPaFSD) and mention it to us in the #api-coverage-requests channel! Since Roblox has a lot of endpoints,
we find it easier to add endpoints as they are needed/requested.

# Contributing
Pull requests and issues are welcome!

Pull requests and issues are welcome!

Please refer to [CONVENTIONS.md](CONVENTIONS.md) for information on conventions used in this crate.

Additional resources used to help make this crate are available in [RESOURCES.md](RESOURCES.md).

# License

MIT License
18 changes: 18 additions & 0 deletions examples/fetch_user_details_by_username.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use roboat::ClientBuilder;

const USERNAME: &str = "Builderman";

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = ClientBuilder::new().build();

let users = vec![USERNAME.to_owned()];
let all_username_user_details = client.username_user_details(users, true).await?;
let username_user_details = all_username_user_details.first().ok_or("User not found")?;

println!("Username: {}", username_user_details.username);
println!("Display Name: {}", username_user_details.display_name);
println!("ID: {}", username_user_details.id);

Ok(())
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
//! - Fetch Username - [`Client::username`]
//! - Fetch Display Name - [`Client::display_name`]
//! - User Search - [`Client::user_search`]
//! - Username User Search - [`Client::username_user_search`]
//! - Fetch User Details - [`Client::user_details`]
//! * UNDER CONSTRUCTION
//! - Upload Classic Clothing To Group - [`Client::upload_classic_clothing_to_group`]
Expand Down
94 changes: 94 additions & 0 deletions src/users/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ mod request_types;
const AUTHENTICATED_USER_DETAILS_API: &str = "https://users.roblox.com/v1/users/authenticated";
const USERS_SEARCH_API: &str = "https://users.roblox.com/v1/users/search";
const USER_DETAILS_API: &str = "https://users.roblox.com/v1/users/{user_id}";
const USER_FROM_USERNAME_API: &str = "https://users.roblox.com/v1/usernames/users";

// TODO: try to make a unified user details struct

/// Basic information about the account of the Roblosecurity. Retrieved
/// from <https://users.roblox.com/v1/users/authenticated>.
Expand Down Expand Up @@ -41,6 +44,20 @@ pub struct UserDetails {
pub has_verified_badge: bool,
}

/// The details of a user. Fetched from <https://users.roblox.com/v1/usernames/users>.
#[allow(missing_docs)]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Serialize, Deserialize)]
pub struct UsernameUserDetails {
pub requested_username: String,
#[serde(alias = "name")]
pub username: String,
#[serde(alias = "displayName")]
pub display_name: String,
pub id: u64,
#[serde(alias = "hasVerifiedBadge")]
pub has_verified_badge: bool,
}

impl Client {
/// Grabs information about the user from <https://catalog.roblox.com/v1/catalog/items/details> using the
/// Roblosecurity inside the client.
Expand Down Expand Up @@ -138,6 +155,11 @@ impl Client {

/// Fetches user details using <https://users.roblox.com/v1/users/{user_id}>.
///
/// For bulk fetching, it is recommended to use [`Client::username_user_details`]
/// instead. This is because more users can be fetched at once using that endpoint.
/// The only downside of this is that you can only search using usernames instead
/// of user IDs.
///
/// # Notes
/// * Does not require a valid roblosecurity.
///
Expand Down Expand Up @@ -174,4 +196,76 @@ impl Client {

Ok(user_details)
}

/// Fetches user details using <https://users.roblox.com/v1/usernames/users>.
///
/// This endpoint uses a post request instead of a get request so
/// it can be used to retrieve information about multiple users at once.
///
/// To fetch a single user, or to fetch a user using a user ID instead of a username,
/// use [`Client::user_details`] instead.
///
/// # Notes
/// * Does not require a valid roblosecurity.
/// * This is virtually the same as [`Client::user_details`] except that it can
/// fetch multiple users at once, and it searches using usernames instead of user IDs.
/// * The usernames are not case sensitive.
///
/// # Errors
/// * All errors under [Standard Errors](#standard-errors).
///
/// # Example
///
/// ```no_run
/// use roboat::ClientBuilder;
///
/// const USERNAME: &str = "Builderman";
///
/// # #[tokio::main]
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let client = ClientBuilder::new().build();
///
/// let users = vec![USERNAME.to_owned()];
/// let all_username_user_details = client.username_user_details(users, true).await?;
/// let username_user_details = all_username_user_details.first().ok_or("User not found")?;
///
/// println!("Username: {}", username_user_details.username);
/// println!("Display Name: {}", username_user_details.display_name);
/// println!("ID: {}", username_user_details.id);
///
/// # Ok(())
/// # }
/// ```
pub async fn username_user_details(
&self,
usernames: Vec<String>,
exclude_banned_users: bool,
) -> Result<Vec<UsernameUserDetails>, RoboatError> {
let request_result = self
.reqwest_client
.post(USER_FROM_USERNAME_API)
.json(&request_types::UsernameUserDetailsRequest {
usernames,
exclude_banned_users,
})
.send()
.await;

let response = Self::validate_request_result(request_result).await?;
let raw =
Self::parse_to_raw::<request_types::UsernameUserDetailsResponse>(response).await?;

let users = raw
.data
.into_iter()
.map(|user| UsernameUserDetails {
requested_username: user.requested_username,
username: user.name,
display_name: user.display_name,
id: user.id,
has_verified_badge: user.has_verified_badge,
})
.collect();
Ok(users)
}
}
21 changes: 21 additions & 0 deletions src/users/request_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,24 @@ pub(super) struct UserSearchUserInformationRaw {
pub previous_usernames: Vec<String>,
pub display_name: String,
}

#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(super) struct UsernameUserDetailsRequest {
pub usernames: Vec<String>,
pub exclude_banned_users: bool,
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(super) struct UsernameUserInformationRaw {
pub requested_username: String,
pub has_verified_badge: bool,
pub id: u64,
pub name: String,
pub display_name: String,
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(super) struct UsernameUserDetailsResponse {
pub data: Vec<UsernameUserInformationRaw>,
}

0 comments on commit 283c903

Please sign in to comment.