roblox_api/api/private_messages/
v1.rs

1use serde::{Deserialize, Serialize};
2
3use crate::{DateTime, Error, Paging, client::Client};
4
5pub const URL: &str = "https://privatemessages.roblox.com/v1";
6
7#[derive(Copy, Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
8#[serde(rename_all = "lowercase")]
9pub enum MessageTab {
10    #[default]
11    Inbox,
12    Sent,
13    Archive,
14}
15
16#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
17#[serde(rename_all = "camelCase")]
18pub struct User {
19    pub id: u64,
20    pub name: String,
21    pub display_name: String,
22    #[serde(rename = "hasVerifiedBadge")]
23    pub is_verified: bool,
24}
25
26#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
27#[serde(rename_all = "camelCase")]
28pub struct Message {
29    pub id: u64,
30    pub subject: String,
31    pub body: String,
32
33    pub sender: User,
34    pub recipient: User,
35
36    pub created: DateTime,
37    pub updated: DateTime,
38
39    pub is_read: bool,
40    pub is_system_message: bool,
41    pub is_report_abuse_displayed: bool,
42}
43
44#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
45pub struct Announcement {
46    pub id: u64,
47    pub subject: String,
48    pub body: String,
49
50    pub sender: User,
51
52    pub created: DateTime,
53    pub updated: DateTime,
54}
55
56#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
57#[serde(rename_all = "camelCase")]
58pub struct Announcements {
59    pub collection: Vec<Announcement>,
60    pub total_collection_size: u64,
61}
62
63#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
64#[serde(rename_all = "camelCase")]
65pub struct Messages {
66    pub collection: Vec<Message>,
67    pub total_collection_size: u64,
68    pub total_pages: u64,
69    #[serde(rename = "pageNumber")]
70    pub current_page: u64,
71}
72
73impl std::fmt::Display for MessageTab {
74    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
75        write!(
76            f,
77            "{}",
78            match self {
79                MessageTab::Inbox => "inbox",
80                MessageTab::Sent => "sent",
81                MessageTab::Archive => "archive",
82            }
83        )
84    }
85}
86
87async fn generic_message_action(
88    client: &mut Client,
89    path: &str,
90    ids: &[u64],
91) -> Result<Vec<u64>, Error> {
92    #[derive(Debug, Serialize)]
93    struct Request<'a> {
94        #[serde(rename = "messageIds")]
95        ids: &'a [u64],
96    }
97
98    let result = client
99        .requestor
100        .client
101        .post(format!("{URL}/messages/{path}"))
102        .json(&Request { ids })
103        .headers(client.requestor.default_headers.clone())
104        .send()
105        .await;
106
107    #[derive(Debug, Deserialize)]
108    struct Response {
109        #[serde(rename = "failedMessages")]
110        failed: Vec<u64>,
111    }
112
113    let response = client.validate_response(result).await?;
114    Ok(client
115        .requestor
116        .parse_json::<Response>(response)
117        .await?
118        .failed)
119}
120
121pub async fn unread_count(client: &mut Client) -> Result<u64, Error> {
122    let result = client
123        .requestor
124        .client
125        .get(format!("{URL}/messages/unread/count"))
126        .headers(client.requestor.default_headers.clone())
127        .send()
128        .await;
129
130    #[derive(Debug, Deserialize)]
131    struct Response {
132        count: u64,
133    }
134
135    let response = client.validate_response(result).await?;
136    Ok(client
137        .requestor
138        .parse_json::<Response>(response)
139        .await?
140        .count)
141}
142
143/// The paging cursor is a page number
144pub async fn messages(
145    client: &mut Client,
146    tab: MessageTab,
147    paging: Paging<'_>,
148) -> Result<Messages, Error> {
149    let limit = paging.limit.unwrap_or(100).to_string();
150    let cursor = match paging.cursor {
151        Some(cursor) => cursor.to_string(),
152        None => String::new(),
153    };
154
155    let result = client
156        .requestor
157        .client
158        .get(format!("{URL}/messages"))
159        .query(&[
160            ("messageTab", tab.to_string()),
161            ("pageNumber", cursor),
162            ("pageSize", limit),
163        ])
164        .headers(client.requestor.default_headers.clone())
165        .send()
166        .await;
167
168    let response = client.validate_response(result).await?;
169    client.requestor.parse_json::<Messages>(response).await
170}
171
172pub async fn announcements(client: &mut Client) -> Result<Announcements, Error> {
173    let result = client
174        .requestor
175        .client
176        .get(format!("{URL}/announcements"))
177        .headers(client.requestor.default_headers.clone())
178        .send()
179        .await;
180
181    let response = client.validate_response(result).await?;
182    client.requestor.parse_json::<Announcements>(response).await
183}
184
185pub async fn archive(client: &mut Client, ids: &[u64]) -> Result<Vec<u64>, Error> {
186    generic_message_action(client, "archive", ids).await
187}
188
189pub async fn unarchive(client: &mut Client, ids: &[u64]) -> Result<Vec<u64>, Error> {
190    generic_message_action(client, "unarchive", ids).await
191}
192
193pub async fn mark_as_read(client: &mut Client, ids: &[u64]) -> Result<Vec<u64>, Error> {
194    generic_message_action(client, "mark-read", ids).await
195}
196
197pub async fn mark_as_unread(client: &mut Client, ids: &[u64]) -> Result<Vec<u64>, Error> {
198    generic_message_action(client, "mark-unread", ids).await
199}