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::{EnumIter, IntoEnumIterator};
11
12#[derive(Clone, Debug, Deserialize, 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
41impl std::fmt::Display for DateTime {
42 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43 write!(f, "{}", self.0)
44 }
45}
46
47#[derive(Debug)]
48pub enum Error {
49 ApiError(ApiError),
50 BadResponse,
51 ReqwestError(reqwest::Error),
52 IoError(std::io::Error),
53}
54
55#[derive(Clone, Debug, PartialEq, Eq)]
56pub enum ApiError {
57 Internal,
58 BadRequest,
59 RequestMissingArgument(String),
60 Ratelimited,
61 Unknown(u16),
62 Unauthorized,
63 InvalidBirthdate,
64 InvalidDisplayName,
65 InvalidGender,
66 UserNotFound,
67 InvalidUserId,
68 PinIsLocked,
69 TokenValidation,
70 CaptchaFailed,
71 ChallengeRequired(Challenge),
72 ChallengeFailed,
73 InvalidChallengeId,
74 InvalidTwoStepVerificationCode,
75 TwoStepVerificationMaintenance,
76 Multiple(Vec<ApiError>),
77 PermissionError,
78 AccontLocked,
79 AccountIssue,
80 InvalidCredentials,
81 UnverifiedCredentials,
82 ExistingLoginSession,
83 DefaultLoginRequired,
84 VNGAppLoginRequired,
85 LuoBuAppLoginRequired,
86 SocialNetworkLoginRequired,
87 InvalidAssetId,
88 InvalidBrowserTrackerId,
89 AlreadyInGroup,
90 AlreadyInGroupRequests,
91 UnsupportedSortOrder,
92}
93
94#[repr(u8)]
95#[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq, EnumIter)]
96pub enum AssetTypeId {
97 Image = 1,
98 TShirt,
99 Audio,
100 Mesh,
101 Lua,
102 Hat = 8,
103 Place,
104 Model,
105 Shirt,
106 Pants,
107 Decal,
108 Head = 17,
109 Face,
110 Gear,
111 Badge = 21,
112 Animation = 24,
113 Torso = 27,
114 RightArm,
115 LeftArm,
116 LeftLeg,
117 RightLeg,
118 Package,
119 YouTubeVideo,
120 Gamepass,
121 Plugin = 38,
122 MeshPart = 40,
123 HairAccessory,
124 FaceAccessory,
125 NeckAccessory,
126 ShoulderAccessory,
127 FrontAccessory,
128 BackAccessory,
129 WaistAccessory,
130 ClimbAnimation,
131 DeathAnimation,
132 FallAnimation,
133 IdleAnimation,
134 JumpAnimation,
135 RunAnimation,
136 SwimAnimation,
137 WalkAnimation,
138 PoseAnimation,
139 EarAccessory,
140 EyeAccessory,
141 EmoteAnimation = 61,
142 Video,
143 TShirtAccessory = 64,
144 ShirtAccessory,
145 PantsAccessory,
146 JacketAccessory,
147 SweaterAccessory,
148 ShortsAccessory,
149 LeftShoeAccessory,
150 RightShoeAccessory,
151 DressSkirtAccessory,
152 FontFamily,
153 EyebrowAccessory = 76,
154 EyelashAccessory,
155 MoodAnimation,
156 DynamicHead,
157}
158
159#[repr(u8)]
160#[derive(Clone, Debug, Default, Serialize, PartialEq, Eq)]
161pub enum Currency {
162 #[default]
163 Robux = 1,
164 Tickets,
165}
166
167#[derive(Clone, Copy, Debug, PartialEq, Eq)]
168pub struct Paging<'a> {
169 pub cursor: Option<&'a str>,
170 pub limit: Option<u16>,
171 pub order: Option<SortOrder>,
172}
173
174#[derive(Clone, Copy, Debug, Default, Serialize, PartialEq, Eq)]
175pub enum SortOrder {
176 #[default]
177 #[serde(rename = "Asc")]
178 Ascending,
179 #[serde(rename = "Desc")]
180 Descending,
181}
182
183impl std::fmt::Display for AssetTypeId {
184 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
185 write!(f, "{:?}", self)
186 }
187}
188
189impl TryFrom<&str> for AssetTypeId {
190 type Error = &'static str;
191
192 fn try_from(value: &str) -> Result<Self, Self::Error> {
193 for kind in AssetTypeId::iter() {
194 if kind.to_string().as_str() == value {
195 return Ok(kind);
196 }
197 }
198
199 Err("Failed to convert string to AssetTypeId")
200 }
201}
202
203impl TryFrom<u8> for AssetTypeId {
204 type Error = &'static str;
205
206 fn try_from(value: u8) -> Result<Self, Self::Error> {
207 for kind in AssetTypeId::iter() {
208 if kind as u8 == value {
209 return Ok(kind);
210 }
211 }
212
213 Err("Failed to convert u8 to AssetTypeId")
214 }
215}
216
217impl std::fmt::Display for SortOrder {
218 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
219 write!(
220 f,
221 "{}",
222 match self {
223 SortOrder::Ascending => "Asc",
224 SortOrder::Descending => "Desc",
225 }
226 )
227 }
228}
229
230impl Default for Paging<'_> {
231 fn default() -> Self {
232 Self {
233 cursor: None,
234 limit: Some(10),
235 order: Some(SortOrder::Ascending),
236 }
237 }
238}
239
240impl<'a> Paging<'a> {
241 pub fn new(
242 cursor: Option<&'a str>,
243 limit: Option<u16>,
244 order: Option<SortOrder>,
245 ) -> Paging<'a> {
246 Self {
247 cursor,
248 limit,
249 order,
250 }
251 }
252}