roblox_api/api/platform_chat/
v1.rs1use std::collections::HashMap;
2
3use serde::{Deserialize, Serialize};
4
5use crate::{DateTime, Paging, endpoint};
6
7pub const URL: &str = "https://apis.roblox.com/platform-chat-api/v1";
8
9#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
10#[serde(rename_all = "snake_case")]
11pub enum ConversationType {
12 OneToOne,
13 Group,
14}
15
16#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
17#[serde(rename_all = "snake_case")]
18pub enum ConversationSource {
19 Channels,
20 Friends,
21}
22
23#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
24pub struct ConversationUser {
25 pub id: u64,
26 pub name: String,
27 pub display_name: String,
28 pub combined_name: String,
30 pub is_verified: bool,
31}
32
33#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
34pub struct Message {
35 pub id: String,
36 pub content: String,
37 #[serde(rename = "type")]
38 pub kind: String, #[serde(rename = "sender_user_id")]
41 pub sender_id: u64,
42 pub replies_to: Option<()>, #[serde(rename = "created_at")]
45 pub created: DateTime,
46
47 pub moderation_type: String, pub is_deleted: bool,
50 pub is_badgeable: bool,
51 pub is_previewable: bool,
52}
53
54#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
55pub struct Conversation {
56 pub id: Option<String>,
57 pub name: String,
58 #[serde(rename = "type")]
59 pub kind: ConversationType,
60 pub source: String, #[serde(rename = "created_by")]
63 pub creator_id: Option<u64>,
64 #[serde(rename = "participant_user_ids")]
65 pub participants: Vec<u64>,
66 #[serde(rename = "user_data")]
67 pub users: HashMap<String, ConversationUser>,
70
71 pub messages: Vec<Message>,
72 pub preview_message: Option<Message>,
73
74 pub sort_index: u64,
75 pub unread_message_count: u64,
76
77 #[serde(rename = "created_at")]
78 pub created: DateTime,
79 #[serde(rename = "updated_at")]
80 pub updated: DateTime,
81
82 pub status: Option<String>, pub moderation_type: Option<String>, pub user_pending_status: Option<String>, pub participant_pending_status: Option<String>, pub osa_acknowledgement_status: String, pub is_default_name: bool,
90}
91
92#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
93pub struct Conversations {
94 pub conversations: Vec<Conversation>,
95 pub next_cursor: Option<String>,
96 pub previous_cursor: Option<String>,
97}
98
99#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
100pub struct ConversationMessages {
101 pub messages: Vec<Message>,
102 pub next_cursor: Option<String>,
103 pub previous_cursor: Option<String>,
104}
105
106#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
107pub struct ConversationMetadata {
108 pub global_unread_count: u64,
109 pub global_unread_message_count: u64,
110}
111
112#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
113pub struct ParticipantMetadata {
114 pub id: u64,
115 pub is_pending: bool,
116}
117
118#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
119pub struct ConversationsParticipantMetadata {
120 pub id: String,
121 pub participants: Vec<ParticipantMetadata>,
122}
123
124#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
125pub struct ConversationMarkedStatus {
126 #[serde(rename = "conversation_id")]
127 pub id: String,
128 pub status: String, }
130
131#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
132pub struct ConversationCreateRequest {
133 pub name: String,
134 pub users: Vec<u64>,
135}
136
137endpoint! {
138 conversation_metadata() -> ConversationMetadata {
139 GET "{URL}/get-conversation-metadata";
140 }
141
142 conversations_participant_metadata(ids: &[&str]) -> Vec<ConversationsParticipantMetadata> {
143 POST "{URL}/get-conversations-participants-metadata";
144 types {
145 Request<'a> { ids("conversation_ids"): &'a [&'a str] }
146 Response { metadata("conversation_participants_metadata"): HashMap<String, ParticipantsMetadata> }
147 ParticipantsMetadata { participants_metadata: HashMap<String, ParticipantPending> }
148 ParticipantPending { is_pending: bool }
149 }
150 body_serialize { Request { ids } }
151 map |r: Response| {
152 let mut metadata = Vec::new();
153 for (conv_id, v) in &r.metadata {
154 let mut participants = Vec::new();
155 for (user_id, pending) in &v.participants_metadata {
156 participants.push(ParticipantMetadata {
157 id: user_id.parse().unwrap(),
158 is_pending: pending.is_pending,
159 });
160 }
161 metadata.push(ConversationsParticipantMetadata {
162 id: conv_id.to_owned(),
163 participants,
164 });
165 }
166 metadata
167 }
168 }
169
170 conversations(ids: &[&str]) -> Conversations {
171 POST "{URL}/get-conversations";
172 types {
173 Request<'a> {
174 ids: &'a [&'a str],
175 include_messages: bool,
176 include_user_data: bool,
177 include_participants: bool,
178 }
179 }
180 body_serialize {
181 Request { ids, include_messages: true, include_user_data: true, include_participants: true }
182 }
183 }
184
185 user_conversations(paging: Paging<'_>) -> Conversations {
186 GET "{URL}/get-user-conversations";
187 prelude {
188 let limit = paging.limit.unwrap_or(20).to_string();
189 let cursor_str = match paging.cursor {
190 Some(c) => c.to_string(),
191 None => String::new(),
192 };
193 }
194 query {
195 "cursor" => &cursor_str,
196 "include_user_data" => "true",
197 "pageSize" => &limit,
198 }
199 }
200
201 conversation_messages(id: &str) -> ConversationMessages {
202 GET "{URL}/get-conversation-messages";
203 query { "conversation_id" => id }
204 }
205
206 send_messages_in_conversation(id: &str, messages: &[&str]) -> ConversationMessages {
208 POST "{URL}/send-messages";
209 types {
210 MessageToPost { content: String }
211 Request<'a> { id("conversation_id"): &'a str, messages: &'a [MessageToPost] }
212 }
213 prelude {
214 let msgs: Vec<MessageToPost> = messages.iter().map(|x| MessageToPost { content: x.to_string() }).collect();
215 }
216 body_serialize { Request { id, messages: &msgs } }
217 }
218
219 update_typing_status_in_conversation(id: &str) -> String {
220 POST "{URL}/update-typing-status";
221 types {
222 Request<'a> { id("conversation_id"): &'a str }
223 Response { status: String }
224 }
225 body_serialize { Request { id } }
226 map |r: Response| r.status
227 }
228
229 add_users_to_conversation(id: &str, users: &[u64]) -> String {
230 POST "{URL}/add-users";
231 types {
232 Request<'a> { id("conversation_id"): &'a str, users("user_ids"): &'a [u64] }
233 Response { status: String }
234 }
235 body_serialize { Request { id, users } }
236 map |r: Response| r.status
237 }
238
239 remove_users_from_conversation(id: &str, users: &[u64]) -> String {
240 POST "{URL}/remove-users";
241 types {
242 Request<'a> { id("conversation_id"): &'a str, users("user_ids"): &'a [u64] }
243 Response { status: String }
244 }
245 body_serialize { Request { id, users } }
246 map |r: Response| r.status
247 }
248
249 create_conversations(conversations: &[ConversationCreateRequest]) -> Conversations {
250 POST "{URL}/create-conversations";
251 types {
252 ConversationToCreate {
253 name: String,
254 kind("type"): String,
255 users("participant_user_ids"): Vec<u64>,
256 }
257 Request<'a> { conversations: &'a [ConversationToCreate], include_user_data: bool }
258 }
259 prelude {
260 let convs: Vec<ConversationToCreate> = conversations.iter().map(|x| ConversationToCreate {
261 name: x.name.clone(),
262 kind: "group".to_string(),
263 users: x.users.clone(),
264 }).collect();
265 }
266 body_serialize { Request { conversations: &convs, include_user_data: true } }
267 }
268
269 rename_conversations(ids: &[&str], names: &[&str]) -> Conversations {
270 POST "{URL}/update-conversations";
271 types {
272 ConversationToUpdate { id: String, name: String }
273 Request<'a> { conversations: &'a [ConversationToUpdate] }
274 }
275 prelude {
276 let updates: Vec<ConversationToUpdate> = ids.iter()
277 .zip(names.iter())
278 .map(|(id, name)| ConversationToUpdate { id: id.to_string(), name: name.to_string() })
279 .collect();
280 }
281 body_serialize { Request { conversations: &updates } }
282 }
283
284 mark_conversations_as_read(ids: &[&str]) -> Vec<ConversationMarkedStatus> {
285 POST "{URL}/mark-conversations";
286 types {
287 Request<'a> { ids("conversation_ids"): &'a [&'a str] }
288 Response { results: Vec<ConversationMarkedStatus> }
289 }
290 body_serialize { Request { ids } }
291 map |r: Response| r.results
292 }
293}