Skip to main content

roblox_api/api/badges/
v1.rs

1use serde::de::DeserializeOwned;
2use serde::{Deserialize, Serialize};
3use strum_macros::{Display, EnumString};
4
5use crate::{DateTime, Error, Paging, client::Client};
6
7pub const URL: &str = "https://badges.roblox.com/v1";
8
9#[derive(Copy, Clone, Debug, PartialEq, Eq, Display, EnumString)]
10pub enum BadgeSortBy {
11    Rank,
12    DateCreated,
13}
14
15// TODO: use CreatorType instead
16#[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq, Display, EnumString)]
17pub enum BadgeCreatorType {
18    User,
19    Group,
20}
21
22#[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq, Display, EnumString)]
23pub enum BadgeAwarderType {
24    Place,
25}
26
27#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
28#[serde(rename_all = "camelCase")]
29pub struct BadgeStatistics {
30    #[serde(rename = "pastDayAwardedCount")]
31    pub awarded_today: u32,
32    #[serde(rename = "awardedCount")]
33    pub awarded_total: u32,
34    pub win_rate_percentage: f32,
35}
36
37#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
38pub struct BadgeCreator {
39    pub id: u64,
40    pub name: String,
41    #[serde(rename = "type")]
42    pub kind: BadgeCreatorType,
43}
44
45#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
46pub struct BadgeAwarder {
47    pub id: u64,
48    #[serde(rename = "type")]
49    pub kind: BadgeAwarderType,
50}
51
52#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
53#[serde(rename_all = "camelCase")]
54pub struct BadgeUniverse {
55    pub id: u64,
56    pub name: String,
57    pub root_place_id: u64,
58}
59
60#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
61#[serde(rename_all = "camelCase")]
62pub struct Badge {
63    pub id: u64,
64    pub name: String,
65    pub description: String,
66
67    pub display_name: String,
68    pub display_description: String,
69
70    pub enabled: bool,
71
72    pub created: DateTime,
73    pub updated: DateTime,
74
75    pub icon_image_id: u64,
76    pub display_icon_image_id: u64,
77
78    pub statistics: BadgeStatistics,
79
80    pub creator: Option<BadgeCreator>,
81    pub awarder: Option<BadgeAwarder>,
82    #[serde(rename = "awardingUniverse")]
83    pub universe: Option<BadgeUniverse>,
84}
85
86#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
87pub struct BadgesResponse {
88    #[serde(rename = "data")]
89    pub badges: Vec<Badge>,
90    #[serde(rename = "nextPageCursor")]
91    pub next_cursor: Option<String>,
92    #[serde(rename = "previousPageCursor")]
93    pub previous_cursor: Option<String>,
94}
95
96async fn badges_generic<Response: DeserializeOwned>(
97    client: &mut Client,
98    path: &str,
99    sort_by: Option<BadgeSortBy>,
100    paging: Paging<'_>,
101) -> Result<Response, Error> {
102    let limit = paging.limit.unwrap_or(10).to_string();
103    let sort_order = paging.order.unwrap_or_default().to_string();
104    let cursor = match paging.cursor {
105        Some(cursor) => cursor.to_string(),
106        None => String::new(),
107    };
108
109    let sort_by = match sort_by {
110        Some(sort_by) => sort_by.to_string(),
111        None => String::new(),
112    };
113
114    let result = client
115        .requestor
116        .client
117        .get(format!("{URL}/{path}/badges"))
118        .query(&[
119            ("sortBy", sort_by),
120            ("limit", limit),
121            ("sortOrder", sort_order),
122            ("cursor", cursor),
123        ])
124        .headers(client.requestor.default_headers.clone())
125        .send()
126        .await;
127
128    let response = client.requestor.validate_response(result).await?;
129    client.requestor.parse_json::<Response>(response).await
130}
131
132pub async fn information(client: &mut Client, id: u64) -> Result<Badge, Error> {
133    let result = client
134        .requestor
135        .client
136        .get(format!("{URL}/badges/{id}"))
137        .headers(client.requestor.default_headers.clone())
138        .send()
139        .await;
140
141    let response = client.requestor.validate_response(result).await?;
142    client.requestor.parse_json::<Badge>(response).await
143}
144
145pub async fn universe_badges(
146    client: &mut Client,
147    id: u64,
148    sort_by: Option<BadgeSortBy>,
149    paging: Paging<'_>,
150) -> Result<BadgesResponse, Error> {
151    badges_generic::<BadgesResponse>(client, &format!("universes/{id}"), sort_by, paging).await
152}
153
154pub async fn user_badges(
155    client: &mut Client,
156    id: u64,
157    paging: Paging<'_>,
158) -> Result<BadgesResponse, Error> {
159    badges_generic::<BadgesResponse>(client, &format!("users/{id}"), None, paging).await
160}
161
162pub async fn remove(client: &mut Client, id: u64, user_id: u64) -> Result<(), Error> {
163    let result = client
164        .requestor
165        .client
166        .delete(format!("{URL}/user/{user_id}/badges/{id}"))
167        .headers(client.requestor.default_headers.clone())
168        .send()
169        .await;
170
171    let response = client.requestor.validate_response(result).await?;
172    client.requestor.parse_json::<()>(response).await
173}
174
175pub async fn authenticated_remove(client: &mut Client, id: u64) -> Result<(), Error> {
176    let result = client
177        .requestor
178        .client
179        .delete(format!("{URL}/user/badges/{id}"))
180        .headers(client.requestor.default_headers.clone())
181        .send()
182        .await;
183
184    let response = client.requestor.validate_response(result).await?;
185    client.requestor.parse_json::<()>(response).await
186}