Skip to content

Commit

Permalink
Merge pull request #49 from Chloe-Woahie/dev-main
Browse files Browse the repository at this point in the history
v0.23.0
  • Loading branch information
fekie authored May 14, 2023
2 parents 00f3c0b + 98c0b13 commit f952231
Show file tree
Hide file tree
Showing 6 changed files with 233 additions and 2 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.22.0"
version = "0.23.0"

[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 @@ -51,6 +51,8 @@ Documentation can be found [here](https://docs.rs/roboat/).
- Set Group Member Role - [`Client::set_group_member_role`](https://docs.rs/roboat/latest/roboat/struct.Client.html#method.set_group_member_role)
* Presence API - [`presence.roblox.com/*`]
- Register Presence - [`Client::register_presence`](https://docs.rs/roboat/latest/roboat/struct.Client.html#method.register_presence)
* Private Messages API - [`privatemessages.roblox.com/*`]
- Fetch Messages - [`Client::messages`](https://docs.rs/roboat/latest/roboat/struct.Client.html#method.messages)
* Trades API - [`trades.roblox.com/*`]
- Fetch Trades List - [`Client::trades`](https://docs.rs/roboat/latest/roboat/struct.Client.html#method.trades)
* Users API - [`users.roblox.com/*`]
Expand All @@ -70,7 +72,7 @@ Alternatively, you can add a specific version of roboat to your project by addin

```toml
[dependencies]
roboat = "0.22.0"
roboat = "0.23.0"
```

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

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

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

let client = ClientBuilder::new()
.roblosecurity(args.roblosecurity)
.build();

let inbox_type = Inbox;

let (messages, messages_metadata) = client.messages(0, inbox_type).await?;

println!("First Message Subject: {}", messages[0].subject);
println!("Total Messages: {}", messages_metadata.total_message_count);
println!("Total Pages: {}", messages_metadata.total_pages);

Ok(())
}
4 changes: 4 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
//! - Set Group Member Role - [`Client::set_group_member_role`]
//! * Presence API
//! - Register Presence - [`Client::register_presence`]
//! * Private Messages API
//! - Fetch Messages - [`Client::messages`]
//! * Trades API
//! - Fetch Trades List - [`Client::trades`]
//! * Users API
Expand Down Expand Up @@ -206,6 +208,8 @@ pub mod economy;
pub mod groups;
/// A module for endpoints prefixed with <https://presence.roblox.com/*>.
mod presence;
/// A module for endpoints prefixed with <https://privatemessages.roblox.com/*>.
pub mod private_messages;
/// A module for endpoints prefixed with <https://trades.roblox.com/*>.
pub mod trades;
/// A module for endpoints prefixed with <https://users.roblox.com/*>.
Expand Down
154 changes: 154 additions & 0 deletions src/private_messages/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
use crate::{Client, RoboatError};
use reqwest::header;
use serde::{Deserialize, Serialize};

mod request_types;

/// Fun fact, pageSize doesn't actually do anything. It's always 20.
const PRIVATE_MESSAGES_API: &str =
"https://privatemessages.roblox.com/v1/messages?messageTab={message_tab_type}&pageNumber={page_number}&pageSize=20";

/// An enum that corresponds to the different message tabs.
#[allow(missing_docs)]
#[derive(
Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Serialize, Deserialize, Copy,
)]
pub enum MessageTabType {
#[default]
Inbox,
Sent,
Archive,
}

impl std::fmt::Display for MessageTabType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Inbox => write!(f, "inbox"),
Self::Sent => write!(f, "sent"),
Self::Archive => write!(f, "archive"),
}
}
}

/// A private message. This can be from the user's inbox, sent, or archive tab.
#[allow(missing_docs)]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Serialize, Deserialize)]
pub struct Message {
pub message_id: u64,
pub sender_id: u64,
pub sender_username: String,
pub sender_display_name: String,
pub receiver_id: u64,
pub receiver_username: String,
pub receiver_display_name: String,
pub subject: String,
pub body: String,
/// ISO 8601 timestamp of when the message was created.
pub created: String,
/// Whether the message has been read.
pub is_read: bool,
/// Whether the message is from Roblox.
pub is_system_message: bool,
}

/// Contains the metadata of the messages. This includes the total amount of messages
/// and the total amount of 20 message pages.
#[derive(
Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Serialize, Deserialize, Copy,
)]
pub struct MessagesMetadata {
/// The total amount of messages in that message tab.
pub total_message_count: u64,
/// The total amount of pages in that message tab. The page numbers go from 0..total_pages.
pub total_pages: u64,
}

impl Client {
/// Page starts at 0
///
/// Fetches private messages from the specified message tab using <https://privatemessages.roblox.com/v1/messages>.
///
/// # Notes
/// * Requires a valid roblosecurity.
/// * Returns 20 messages at a time.
///
/// # Argument Notes
/// * The page starts at 0.
///
/// # Return Value Notes
/// * The first value in the tuple is a vector of messages.
/// * The second value in the tuple is the metadata of the messages (total count and page amount).
///
/// # Errors
/// * All errors under [Standard Errors](#standard-errors).
/// * All errors under [Auth Required Errors](#auth-required-errors).
///
/// # Example
/// ```no_run
/// use roboat::ClientBuilder;
/// use roboat::private_messages::MessageTabType::Inbox;
///
/// const ROBLOSECURITY: &str = "roblosecurity";
///
/// # #[tokio::main]
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let client = ClientBuilder::new().roblosecurity(ROBLOSECURITY.to_string()).build();
///
/// let inbox_type = Inbox;
///
/// let (messages, messages_metadata) = client.messages(0, inbox_type).await?;
///
/// println!("First Message Subject: {}", messages[0].subject);
/// println!("Total Messages: {}", messages_metadata.total_message_count);
/// println!("Total Pages: {}", messages_metadata.total_pages);
/// # Ok(())
/// # }
/// ```
pub async fn messages(
&self,
page: u64,
message_tab_type: MessageTabType,
) -> Result<(Vec<Message>, MessagesMetadata), RoboatError> {
let cookie_string = self.cookie_string()?;

let url = PRIVATE_MESSAGES_API
.replace("{message_tab_type}", message_tab_type.to_string().as_str())
.replace("{page_number}", page.to_string().as_str());

let request_result = self
.reqwest_client
.get(&url)
.header(header::COOKIE, cookie_string)
.send()
.await;

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

let messages = raw
.collection
.into_iter()
.map(|message| Message {
message_id: message.id as u64,
sender_id: message.sender.id as u64,
sender_username: message.sender.name,
sender_display_name: message.sender.display_name,
receiver_id: message.recipient.id as u64,
receiver_username: message.recipient.name,
receiver_display_name: message.recipient.display_name,
subject: message.subject,
body: message.body,
created: message.created,
is_read: message.is_read,
is_system_message: message.is_system_message,
})
.collect();

let metadata = MessagesMetadata {
total_message_count: raw.total_collection_size as u64,
total_pages: raw.total_pages as u64,
};

Ok((messages, metadata))
}
}
43 changes: 43 additions & 0 deletions src/private_messages/request_types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use serde::{Deserialize, Serialize};

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(super) struct MessagesResponse {
pub collection: Vec<MessageRaw>,
pub total_collection_size: i64,
pub total_pages: i64,
pub page_number: i64,
}

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(super) struct MessageRaw {
pub id: i64,
pub sender: Sender,
pub recipient: Recipient,
pub subject: String,
pub body: String,
pub created: String,
pub updated: String,
pub is_read: bool,
pub is_system_message: bool,
pub is_report_abuse_displayed: bool,
}

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(super) struct Sender {
pub has_verified_badge: bool,
pub id: i64,
pub name: String,
pub display_name: String,
}

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(super) struct Recipient {
pub has_verified_badge: bool,
pub id: i64,
pub name: String,
pub display_name: String,
}

0 comments on commit f952231

Please sign in to comment.