1use iso8601_timestamp::Timestamp;
2use once_cell::sync::Lazy;
3use regex::Regex;
4
5use super::File;
6
7#[cfg(feature = "validator")]
8use validator::Validate;
9
10pub static RE_USERNAME: Lazy<Regex> = Lazy::new(|| Regex::new(r"^(\p{L}|[\d_.-])+$").unwrap());
15
16pub static RE_DISPLAY_NAME: Lazy<Regex> = Lazy::new(|| Regex::new(r"^[^\u200B\n\r]+$").unwrap());
21
22auto_derived_partial!(
23 pub struct User {
25 #[cfg_attr(feature = "serde", serde(rename = "_id"))]
27 pub id: String,
28 pub username: String,
30 pub discriminator: String,
32 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
34 pub display_name: Option<String>,
35 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
37 pub pronouns: Option<String>,
38 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
39 pub avatar: Option<File>,
41 #[cfg_attr(
43 feature = "serde",
44 serde(skip_serializing_if = "Vec::is_empty", default)
45 )]
46 pub relations: Vec<Relationship>,
47
48 #[cfg_attr(
52 feature = "serde",
53 serde(skip_serializing_if = "crate::if_zero_u32", default)
54 )]
55 pub badges: u32,
56 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
58 pub status: Option<UserStatus>,
59
60 #[cfg_attr(
64 feature = "serde",
65 serde(skip_serializing_if = "crate::if_zero_u32", default)
66 )]
67 pub flags: u32,
68 #[cfg_attr(
70 feature = "serde",
71 serde(skip_serializing_if = "crate::if_false", default)
72 )]
73 pub privileged: bool,
74 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
76 pub bot: Option<BotInformation>,
77
78 pub relationship: RelationshipStatus,
80 pub online: bool,
82 },
83 "PartialUser"
84);
85
86auto_derived!(
87 pub enum FieldsUser {
89 Avatar,
90 StatusText,
91 StatusPresence,
92 ProfileContent,
93 ProfileBackground,
94 DisplayName,
95 Pronouns,
96
97 Internal,
99 }
100
101 #[derive(Default)]
103 pub enum RelationshipStatus {
104 #[default]
106 None,
107 User,
109 Friend,
111 Outgoing,
113 Incoming,
115 Blocked,
117 BlockedOther,
119 }
120
121 pub struct Relationship {
123 #[cfg_attr(feature = "serde", serde(rename = "_id"))]
125 pub user_id: String,
126 pub status: RelationshipStatus,
128 }
129
130 pub enum Presence {
132 Online,
134 Idle,
136 Focus,
138 Busy,
140 Invisible,
142 }
143
144 #[derive(Default)]
146 #[cfg_attr(feature = "validator", derive(Validate))]
147 pub struct UserStatus {
148 #[validate(length(min = 0, max = 128))]
150 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
151 pub text: Option<String>,
152 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
154 pub presence: Option<Presence>,
155 }
156
157 #[derive(Default)]
159 #[cfg_attr(feature = "validator", derive(Validate))]
160 pub struct UserProfile {
161 #[validate(length(min = 0, max = 2000))]
163 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
164 pub content: Option<String>,
165 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
167 pub background: Option<File>,
168 }
169
170 #[repr(u32)]
172 pub enum UserBadges {
173 Developer = 1,
175 Translator = 2,
177 Supporter = 4,
179 ResponsibleDisclosure = 8,
181 Founder = 16,
183 PlatformModeration = 32,
185 ActiveSupporter = 64,
187 Paw = 128,
189 EarlyAdopter = 256,
191 ReservedRelevantJokeBadge1 = 512,
193 ReservedRelevantJokeBadge2 = 1024,
195 }
196
197 #[repr(u32)]
199 pub enum UserFlags {
200 SuspendedUntil = 1,
202 Deleted = 2,
204 Banned = 4,
206 Spam = 8,
208 }
209
210 #[cfg_attr(feature = "validator", derive(Validate))]
212 pub struct DataUserProfile {
213 #[cfg_attr(feature = "validator", validate(length(min = 0, max = 2000)))]
215 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
216 pub content: Option<String>,
217 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
219 #[cfg_attr(feature = "validator", validate(length(min = 1, max = 128)))]
220 pub background: Option<String>,
221 }
222
223 #[cfg_attr(feature = "validator", derive(Validate))]
225 pub struct DataEditUser {
226 #[cfg_attr(
228 feature = "validator",
229 validate(length(min = 2, max = 32), regex = "RE_DISPLAY_NAME")
230 )]
231 pub display_name: Option<String>,
232 #[cfg_attr(feature = "validator", validate(length(min = 1, max = 24)))]
234 pub pronouns: Option<String>,
235 #[cfg_attr(feature = "validator", validate(length(min = 1, max = 128)))]
237 pub avatar: Option<String>,
238
239 #[cfg_attr(feature = "validator", validate)]
241 pub status: Option<UserStatus>,
242 #[cfg_attr(feature = "validator", validate)]
246 pub profile: Option<DataUserProfile>,
247
248 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
250 pub badges: Option<i32>,
251 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
253 pub flags: Option<i32>,
254
255 #[cfg_attr(feature = "serde", serde(default))]
257 pub remove: Vec<FieldsUser>,
258 }
259
260 pub struct FlagResponse {
262 pub flags: i32,
264 }
265
266 pub struct MutualResponse {
268 pub users: Vec<String>,
270 pub servers: Vec<String>,
272 pub channels: Vec<String>,
274 }
275
276 pub struct BotInformation {
278 #[cfg_attr(feature = "serde", serde(rename = "owner"))]
280 pub owner_id: String,
281 }
282
283 pub struct DataSendFriendRequest {
285 pub username: String,
287 }
288);
289
290auto_derived_partial!(
291 pub struct UserVoiceState {
293 pub id: String,
294 pub joined_at: Timestamp,
295 pub is_receiving: bool,
296 pub is_publishing: bool,
297 pub screensharing: bool,
298 pub camera: bool,
299 },
300 "PartialUserVoiceState"
301);
302
303pub trait CheckRelationship {
304 fn with(&self, user: &str) -> RelationshipStatus;
305}
306
307impl CheckRelationship for Vec<Relationship> {
308 fn with(&self, user: &str) -> RelationshipStatus {
309 for entry in self {
310 if entry.user_id == user {
311 return entry.status.clone();
312 }
313 }
314
315 RelationshipStatus::None
316 }
317}