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