1pub mod api;
2pub mod challenge;
3pub mod client;
4pub mod ratelimit;
5pub mod validation;
6
7#[macro_use]
8mod endpoint;
9
10use challenge::Challenge;
11use chrono::{Datelike, TimeZone, Utc};
12use serde::{Deserialize, Serialize};
13use strum_macros::{Display, EnumString, FromRepr};
14
15#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
17pub struct DateTime(String);
18impl DateTime {
19 pub fn from_ymd(year: i32, month: u8, day: u8) -> Self {
20 Self(
21 Utc.with_ymd_and_hms(year, month as u32, day as u32, 0, 0, 0)
22 .unwrap()
23 .to_rfc3339(),
24 )
25 }
26
27 pub fn day(&self) -> u8 {
28 chrono::DateTime::parse_from_rfc3339(&self.0).unwrap().day() as u8
29 }
30
31 pub fn month(&self) -> u8 {
32 chrono::DateTime::parse_from_rfc3339(&self.0)
33 .unwrap()
34 .month() as u8
35 }
36
37 pub fn year(&self) -> i32 {
38 chrono::DateTime::parse_from_rfc3339(&self.0)
39 .unwrap()
40 .year()
41 }
42}
43
44#[repr(u8)]
45#[derive(Clone, Copy, Debug, PartialEq, Eq, Display, EnumString, FromRepr)]
46pub enum Gender {
47 None = 1,
48 Male = 2,
49 Female = 3,
50}
51
52#[derive(Debug)]
53pub enum Error {
54 ApiError(ApiError),
55 BadJson,
56 IoError(std::io::Error),
57 ReqwestError(reqwest::Error),
58 #[cfg(feature = "web-socket")]
59 ReqwestWebSocketError(reqwest_websocket::Error),
60}
61
62#[derive(Clone, Debug, PartialEq, Eq, Display)]
63pub enum ApiError {
64 Internal,
65 BadRequest,
66 RequestMissingArgument(String),
67 Ratelimited,
68 Unknown(u16, Option<String>),
69 Unauthorized,
70 InvalidBirthdate,
71 InvalidDisplayName,
72 InvalidGender,
73 InvalidUser,
74 InvalidUserId,
75 PinIsLocked,
76 TokenValidation,
77 CaptchaFailed,
78 ChallengeRequired(Challenge),
79 ChallengeFailed,
80 InvalidChallengeId,
81 InvalidTwoStepVerificationCode,
82 TwoStepVerificationMaintenance,
83 Multiple(Vec<ApiError>),
84 PermissionError,
85 AccontLocked,
86 AccountIssue,
87 InvalidCredentials,
88 UnverifiedCredentials,
89 ExistingLoginSession,
90 DefaultLoginRequired,
91 VNGAppLoginRequired,
92 LuoBuAppLoginRequired,
93 SocialNetworkLoginRequired,
94 InvalidAssetId,
95 InvalidBrowserTrackerId,
96 AlreadyInGroup,
97 AlreadyInGroupRequests,
98 UnsupportedSortOrder,
99 InvalidBadge,
100 ConversationCreationFailed,
101 InvalidConversation,
102 ConversationUserAddFailed,
103 NotEnoughFunds(Currency),
104}
105
106#[repr(u8)]
107#[derive(
108 Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq, Display, EnumString, FromRepr,
109)]
110pub enum AssetTypeId {
111 Image = 1,
112 TShirt,
113 Audio,
114 Mesh,
115 Lua,
116 Hat = 8,
117 Place,
118 Model,
119 Shirt,
120 Pants,
121 Decal,
122 Head = 17,
123 Face,
124 Gear,
125 Badge = 21,
126 Animation = 24,
127 Torso = 27,
128 RightArm,
129 LeftArm,
130 LeftLeg,
131 RightLeg,
132 Package,
133 YouTubeVideo,
134 Gamepass,
135 Plugin = 38,
136 MeshPart = 40,
137 HairAccessory,
138 FaceAccessory,
139 NeckAccessory,
140 ShoulderAccessory,
141 FrontAccessory,
142 BackAccessory,
143 WaistAccessory,
144 ClimbAnimation,
145 DeathAnimation,
146 FallAnimation,
147 IdleAnimation,
148 JumpAnimation,
149 RunAnimation,
150 SwimAnimation,
151 WalkAnimation,
152 PoseAnimation,
153 EarAccessory,
154 EyeAccessory,
155 EmoteAnimation = 61,
156 Video,
157 TShirtAccessory = 64,
158 ShirtAccessory,
159 PantsAccessory,
160 JacketAccessory,
161 SweaterAccessory,
162 ShortsAccessory,
163 LeftShoeAccessory,
164 RightShoeAccessory,
165 DressSkirtAccessory,
166 FontFamily,
167 EyebrowAccessory = 76,
168 EyelashAccessory,
169 MoodAnimation,
170 DynamicHead,
171}
172
173#[repr(u8)]
174#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq, Display)]
175pub enum Currency {
176 #[default]
177 Robux = 1,
178 Tickets,
179}
180
181#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PartialEq, Eq, Display)]
182pub enum SortOrder {
183 #[default]
184 #[serde(rename = "Asc")]
185 Ascending,
186 #[serde(rename = "Desc")]
187 Descending,
188}
189
190#[derive(Clone, Copy, Debug, PartialEq, Eq)]
191pub struct Paging<'a> {
192 pub cursor: Option<&'a str>,
193 pub limit: Option<u16>,
194 pub order: Option<SortOrder>,
195}
196
197impl From<serde_json::Error> for Error {
198 fn from(_error: serde_json::Error) -> Self {
199 Error::BadJson
200 }
201}
202
203impl From<reqwest::Error> for Error {
204 fn from(error: reqwest::Error) -> Self {
205 Error::ReqwestError(error)
206 }
207}
208
209#[cfg(feature = "web-socket")]
210impl From<reqwest_websocket::Error> for Error {
211 fn from(error: reqwest_websocket::Error) -> Self {
212 Error::ReqwestWebSocketError(error)
213 }
214}
215
216impl std::fmt::Display for DateTime {
217 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
218 write!(f, "{}", self.0)
219 }
220}
221
222impl Default for Paging<'_> {
223 fn default() -> Self {
224 Self {
225 cursor: None,
226 limit: Some(10),
227 order: Some(SortOrder::Ascending),
228 }
229 }
230}
231
232impl<'a> Paging<'a> {
233 pub fn new(
234 cursor: Option<&'a str>,
235 limit: Option<u16>,
236 order: Option<SortOrder>,
237 ) -> Paging<'a> {
238 Self {
239 cursor,
240 limit,
241 order,
242 }
243 }
244}