Skip to content

Commit

Permalink
Merge pull request #41 from Chloe-Woahie/dev-main
Browse files Browse the repository at this point in the history
v0.16.2
  • Loading branch information
fekie authored May 8, 2023
2 parents 51c4cb1 + 8f60d8e commit cca03f4
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 4 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ license = "MIT"
name = "roboat"
readme = "README.md"
repository = "https://github.com/Chloe-Woahie/roboat"
version = "0.16.1"
version = "0.16.2"

[dependencies]
reqwest = { version = "0.11.14", default-features=false, features = ["rustls-tls", "json"] }
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ Documentation can be found [here](https://docs.rs/roboat/).
- Fetch Trades List - [`Client::trades`](https://docs.rs/roboat/latest/roboat/struct.Client.html#method.trades)
* Auth API - [`auth.roblox.com/*`]
- Force Refresh X-CSRF-TOKEN - [`Client::force_refresh_xcsrf_token`](https://docs.rs/roboat/latest/roboat/struct.Client.html#method.force_refresh_xcsrf_token)
* Group API - [`groups.roblox.com/*`]
- Fetch Group Roles - [`Client::group_roles`](https://docs.rs/roboat/latest/roboat/struct.Client.html#method.group_roles)
* BEDEV2 API - [`apis.roblox.com/*`]
- Fetch Non-Tradable Limited Details - [`Client::non_tradable_limited_details`](https://docs.rs/roboat/latest/roboat/struct.Client.html#method.non_tradable_limited_details)
- Fetch Collectible Product ID - [`Client::collectible_product_id`](https://docs.rs/roboat/latest/roboat/struct.Client.html#method.collectible_product_id)
Expand All @@ -62,7 +64,7 @@ Alternatively, you can add a specific version of roboat to your project by addin

```toml
[dependencies]
roboat = "0.16.1"
roboat = "0.16.2"
```

# Quick Start Examples
Expand Down
26 changes: 26 additions & 0 deletions examples/fetch_group_roles.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use clap::Parser;
use roboat::ClientBuilder;

#[derive(Parser, Debug)]
struct Args {
#[arg(long, short)]
group_id: u64,
}

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

let roles = client.group_roles(args.group_id).await?;

// Print all roles in order by rank.
for role in roles {
println!(
"Role: {} / ID: {} / Rank: {}",
role.name, role.id, role.rank
);
}

Ok(())
}
74 changes: 74 additions & 0 deletions src/groups/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use crate::{Client, RoboatError};
use serde::{Deserialize, Serialize};

mod request_types;

const GROUP_ROLES_API: &str = "https://groups.roblox.com/v1/groups/{group_id}/roles";

/// A role in a group.
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Role {
/// The ID of the role.
pub id: u64,
/// The name of the role.
pub name: String,
/// A number from 0 to 255 that determines the role's rank, with
/// 255 being the highest rank and 0 being the lowest rank.
pub rank: u8,
/// The number of members in the role.
pub member_count: u64,
}

impl Client {
/// In order by rank starting from lowest rank.
///
/// Returns the roles of a group using <https://groups.roblox.com/v1/groups/{group_id}/roles>.
///
/// # Notes
/// * Does not require a valid roblosecurity.
///
/// # Errors
/// * All errors under [Standard Errors](#standard-errors).
///
/// # Example
///
/// ```no_run
/// use roboat::ClientBuilder;
///
/// const ROBLOSECURITY: &str = "roblosecurity";
/// const GROUP_ID: u64 = 1127093;
///
/// # #[tokio::main]
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let client = ClientBuilder::new().roblosecurity(ROBLOSECURITY.to_string()).build();
///
/// let roles = client.group_roles(GROUP_ID).await?;
///
/// // Print all roles in order by rank
/// for role in roles {
/// println!(
/// "Role: {} / ID: {} / Rank: {}",
/// role.name, role.id, role.rank
/// );
/// }
///
/// # Ok(())
/// # }
/// ```
pub async fn group_roles(&self, group_id: u64) -> Result<Vec<Role>, RoboatError> {
let formatted_url = GROUP_ROLES_API.replace("{group_id}", &group_id.to_string());

let request_result = self.reqwest_client.get(formatted_url).send().await;

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

let mut roles = raw.roles;

// Enforce that the roles are in order by rank in ascending order
roles.sort_by(|a, b| a.rank.cmp(&b.rank));

Ok(roles)
}
}
9 changes: 9 additions & 0 deletions src/groups/request_types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use super::Role;
use serde::{Deserialize, Serialize};

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(super) struct RolesResponse {
pub group_id: i64,
pub roles: Vec<Role>,
}
12 changes: 11 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
//! - Fetch Trades List - [`Client::trades`]
//! * Auth API
//! - Force Refresh Xcsrf - [`Client::force_refresh_xcsrf`]
//! * Group API
//! - Fetch Group Roles - [`Client::group_roles`]
//! * BEDEV2 API
//! - Fetch Non-Tradable Limited Details - [`Client::non_tradable_limited_details`]
//! - Fetch Collectible Product ID - [`Client::collectible_product_id`]
Expand Down Expand Up @@ -182,20 +184,25 @@ pub use bedev2::PurchaseNonTradableLimitedError;
pub use client::{Client, ClientBuilder};
pub use economy::PurchaseTradableLimitedError;

/// A module for endpoints prefixed with <https://auth.roblox.com/*>.
mod auth;
/// A module for endpoints prefixed with <https://apis.roblox.com/*>.
pub mod bedev2;
/// A module for endpoints prefixed with <https://catalog.roblox.com/*>.
pub mod catalog;
/// A module related to the [`Client`] struct.
mod client;
/// A module for endpoints prefixed with <https://economy.roblox.com/*>.
pub mod economy;
/// A module for endpoints prefixed with <https://groups.roblox.com/*>.
pub mod groups;
/// A module for endpoints prefixed with <https://presence.roblox.com/*>.
mod presence;
/// A module for endpoints prefixed with <https://trades.roblox.com/*>.
pub mod trades;
/// A module for endpoints prefixed with <https://users.roblox.com/*>.
pub mod users;
/// A module related to validating requests.
mod validation;

// todo: add manual xcsrf refresh
Expand All @@ -217,10 +224,13 @@ mod validation;
// todo: rename methods and docs to remain consistent over what non-tradable limiteds are called.
// todo: add method to get items from catalog
// todo: make ItemDetails include both price and lowest price
// todo: replace urls with the form GROUP_ROLES_API.replace("{group_id}", &group_id.to_string());
// todo: rename all examples with get_ to fetch_
// todo: sort api coverage by alphabetical order

use serde::{Deserialize, Serialize};

// Used in reqwest header keys.
// Used in request header keys.
const XCSRF_HEADER: &str = "x-csrf-token";
// The user agent used for fussy endpoints.
const USER_AGENT: &str =
Expand Down
2 changes: 1 addition & 1 deletion src/users/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ impl Client {
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let client = ClientBuilder::new().roblosecurity(ROBLOSECURITY.to_string()).build();
///
/// let keyword = "linkmon".to_string();
/// let keyword = KEYWORD.to_string();
/// let users = client.user_search(keyword).await?;
///
/// println!("Found {} users.", users.len());
Expand Down

0 comments on commit cca03f4

Please sign in to comment.