1use serde::{Deserialize, Serialize};
2
3use crate::{DateTime, Error, Paging, client::Client};
4
5pub const URL: &str = "https://groups.roblox.com/v1";
6
7#[derive(Clone, Debug, Deserialize)]
8pub struct GroupUser {
9 #[serde(rename = "userId")]
10 pub id: u64,
11 #[serde(rename = "username")]
12 pub name: String,
13 #[serde(rename = "displayName")]
14 pub display_name: String,
15 #[serde(rename = "hasVerifiedBadge")]
16 pub is_verified: bool,
17}
18
19#[derive(Clone, Debug, Deserialize)]
20pub struct GroupRole {
21 pub id: u64,
22 pub name: String,
23 pub rank: u8,
24}
25
26#[derive(Clone, Debug, Deserialize)]
27pub struct GroupShout {
28 pub body: String,
29 pub poster: GroupUser,
30 pub created: DateTime,
31 pub updated: DateTime,
32}
33
34#[derive(Clone, Debug, Deserialize)]
35pub struct GroupInformation {
36 pub id: u64,
37 pub name: String,
38 pub description: String,
39
40 pub owner: Option<GroupUser>,
41 pub shout: Option<GroupShout>,
42
43 #[serde(rename = "memberCount")]
44 pub member_count: u64,
45 #[serde(rename = "isBuildersClubOnly")]
46 pub premium_only: bool,
47 #[serde(rename = "publicEntryAllowed")]
48 pub is_public: bool,
49 #[serde(rename = "hasVerifiedBadge")]
50 pub is_verified: bool,
51}
52
53pub struct GroupUsers {
54 pub users: Vec<(GroupUser, GroupRole)>,
55 pub next_cursor: Option<String>,
56 pub previous_cursor: Option<String>,
57}
58
59pub async fn information(client: &mut Client, id: u64) -> Result<GroupInformation, Error> {
60 let result = client
61 .requestor
62 .client
63 .get(format!("{URL}/groups/{id}"))
64 .headers(client.requestor.default_headers.clone())
65 .send()
66 .await;
67
68 let response = client.validate_response(result).await?;
69 client
70 .requestor
71 .parse_json::<GroupInformation>(response)
72 .await
73}
74
75pub async fn roles(client: &mut Client, id: u64) -> Result<Vec<GroupRole>, Error> {
76 let result = client
77 .requestor
78 .client
79 .get(format!("{URL}/groups/{id}/roles"))
80 .headers(client.requestor.default_headers.clone())
81 .send()
82 .await;
83
84 #[derive(Clone, Debug, Deserialize)]
85 struct Response {
86 roles: Vec<GroupRole>,
87 }
88
89 let response = client.validate_response(result).await?;
90 Ok(client
91 .requestor
92 .parse_json::<Response>(response)
93 .await?
94 .roles)
95}
96
97pub async fn user_roles(
98 client: &mut Client,
99 id: u64,
100) -> Result<Vec<(GroupInformation, GroupRole)>, Error> {
101 let result = client
102 .requestor
103 .client
104 .get(format!("{URL}/users/{id}/groups/roles"))
105 .headers(client.requestor.default_headers.clone())
106 .send()
107 .await;
108
109 #[derive(Clone, Debug, Deserialize)]
110 struct GroupAndRole {
111 group: GroupInformation,
112 role: GroupRole,
113 }
114
115 #[derive(Clone, Debug, Deserialize)]
116 struct Response {
117 #[serde(rename = "data")]
118 items: Vec<GroupAndRole>,
119 }
120
121 let response = client.validate_response(result).await?;
122 let response = client.requestor.parse_json::<Response>(response).await?;
123
124 let mut roles = Vec::new();
125 for item in &response.items {
126 roles.push((item.group.clone(), item.role.clone()));
127 }
128
129 Ok(roles)
130}
131
132pub async fn users(client: &mut Client, id: u64, paging: Paging<'_>) -> Result<GroupUsers, Error> {
133 let limit = paging.limit.unwrap_or(10).to_string();
134 let sort_order = paging.order.unwrap_or_default().to_string();
135 let cursor = match paging.cursor {
136 Some(cursor) => cursor.to_string(),
137 None => String::new(),
138 };
139
140 let result = client
141 .requestor
142 .client
143 .get(format!("{URL}/groups/{id}/users"))
144 .query(&[
145 ("limit", limit),
146 ("sortOrder", sort_order),
147 ("cursor", cursor),
148 ])
149 .headers(client.requestor.default_headers.clone())
150 .send()
151 .await;
152
153 #[derive(Clone, Debug, Deserialize)]
154 struct User {
155 user: GroupUser,
156 role: GroupRole,
157 }
158
159 #[derive(Clone, Debug, Deserialize)]
160 struct Response {
161 #[serde(rename = "data")]
162 users: Vec<User>,
163 #[serde(rename = "nextPageCursor")]
164 next_cursor: Option<String>,
165 #[serde(rename = "previousPageCursor")]
166 previous_cursor: Option<String>,
167 }
168
169 let response = client.validate_response(result).await?;
170 let response = client.requestor.parse_json::<Response>(response).await?;
171
172 let mut users = Vec::new();
173 for user in response.users {
174 users.push((user.user, user.role))
175 }
176
177 Ok(GroupUsers {
178 users,
179 next_cursor: response.next_cursor,
180 previous_cursor: response.previous_cursor,
181 })
182}
183
184pub async fn join(client: &mut Client, id: u64) -> Result<(), Error> {
185 #[derive(Serialize)]
186 struct Request<'a> {
187 #[serde(rename = "sessionId")]
188 session_id: &'a str,
189 #[serde(rename = "redemptionToken")]
190 redemption_token: &'a str,
191 }
192
193 let result = client
194 .requestor
195 .client
196 .post(format!("{URL}/groups/{id}/users"))
197 .headers(client.requestor.default_headers.clone())
198 .json(&Request {
199 session_id: "",
200 redemption_token: "",
201 })
202 .send()
203 .await;
204
205 client.validate_response(result).await?;
206 Ok(())
207}
208
209pub async fn remove_join_request(client: &mut Client, id: u64, user_id: u64) -> Result<(), Error> {
210 #[derive(Serialize)]
211 struct Request {}
212
213 let result = client
214 .requestor
215 .client
216 .delete(format!("{URL}/groups/{id}/join-requests/users/{user_id}"))
217 .json(&Request {})
218 .headers(client.requestor.default_headers.clone())
219 .send()
220 .await;
221
222 client.validate_response(result).await?;
223 Ok(())
224}
225
226pub async fn remove(client: &mut Client, id: u64, user_id: u64) -> Result<(), Error> {
227 #[derive(Serialize)]
228 struct Request {}
229
230 let result = client
231 .requestor
232 .client
233 .delete(format!("{URL}/groups/{id}/users/{user_id}"))
234 .headers(client.requestor.default_headers.clone())
235 .json(&Request {})
236 .send()
237 .await;
238
239 client.validate_response(result).await?;
240 Ok(())
241}