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"))]
36 pub avatar: Option<File>,
38 #[cfg_attr(
40 feature = "serde",
41 serde(skip_serializing_if = "Vec::is_empty", default)
42 )]
43 pub relations: Vec<Relationship>,
44
45 #[cfg_attr(
49 feature = "serde",
50 serde(skip_serializing_if = "crate::if_zero_u32", default)
51 )]
52 pub badges: u32,
53 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
55 pub status: Option<UserStatus>,
56
57 #[cfg_attr(
61 feature = "serde",
62 serde(skip_serializing_if = "crate::if_zero_u32", default)
63 )]
64 pub flags: u32,
65 #[cfg_attr(
67 feature = "serde",
68 serde(skip_serializing_if = "crate::if_false", default)
69 )]
70 pub privileged: bool,
71 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
73 pub bot: Option<BotInformation>,
74
75 pub relationship: RelationshipStatus,
77 pub online: bool,
79 },
80 "PartialUser"
81);
82
83auto_derived!(
84 pub enum FieldsUser {
86 Avatar,
87 StatusText,
88 StatusPresence,
89 ProfileContent,
90 ProfileBackground,
91 DisplayName,
92
93 Internal,
95 }
96
97 #[derive(Default)]
99 pub enum RelationshipStatus {
100 #[default]
102 None,
103 User,
105 Friend,
107 Outgoing,
109 Incoming,
111 Blocked,
113 BlockedOther,
115 }
116
117 pub struct Relationship {
119 #[cfg_attr(feature = "serde", serde(rename = "_id"))]
121 pub user_id: String,
122 pub status: RelationshipStatus,
124 }
125
126 pub enum Presence {
128 Online,
130 Idle,
132 Focus,
134 Busy,
136 Invisible,
138 }
139
140 #[derive(Default)]
142 #[cfg_attr(feature = "validator", derive(Validate))]
143 pub struct UserStatus {
144 #[validate(length(min = 0, max = 128))]
146 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
147 pub text: Option<String>,
148 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
150 pub presence: Option<Presence>,
151 }
152
153 #[derive(Default)]
155 #[cfg_attr(feature = "validator", derive(Validate))]
156 pub struct UserProfile {
157 #[validate(length(min = 0, max = 2000))]
159 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
160 pub content: Option<String>,
161 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
163 pub background: Option<File>,
164 }
165
166 #[repr(u32)]
168 pub enum UserBadges {
169 Developer = 1,
171 Translator = 2,
173 Supporter = 4,
175 ResponsibleDisclosure = 8,
177 Founder = 16,
179 PlatformModeration = 32,
181 ActiveSupporter = 64,
183 Paw = 128,
185 EarlyAdopter = 256,
187 ReservedRelevantJokeBadge1 = 512,
189 ReservedRelevantJokeBadge2 = 1024,
191 }
192
193 #[repr(u32)]
195 pub enum UserFlags {
196 SuspendedUntil = 1,
198 Deleted = 2,
200 Banned = 4,
202 Spam = 8,
204 }
205
206 #[cfg_attr(feature = "validator", derive(Validate))]
208 pub struct DataUserProfile {
209 #[cfg_attr(feature = "validator", validate(length(min = 0, max = 2000)))]
211 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
212 pub content: Option<String>,
213 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
215 #[cfg_attr(feature = "validator", validate(length(min = 1, max = 128)))]
216 pub background: Option<String>,
217 }
218
219 #[cfg_attr(feature = "validator", derive(Validate))]
221 pub struct DataEditUser {
222 #[cfg_attr(
224 feature = "validator",
225 validate(length(min = 2, max = 32), regex = "RE_DISPLAY_NAME")
226 )]
227 pub display_name: Option<String>,
228 #[cfg_attr(feature = "validator", validate(length(min = 1, max = 128)))]
230 pub avatar: Option<String>,
231
232 #[cfg_attr(feature = "validator", validate)]
234 pub status: Option<UserStatus>,
235 #[cfg_attr(feature = "validator", validate)]
239 pub profile: Option<DataUserProfile>,
240
241 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
243 pub badges: Option<i32>,
244 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
246 pub flags: Option<i32>,
247
248 #[cfg_attr(feature = "serde", serde(default))]
250 pub remove: Vec<FieldsUser>,
251 }
252
253 pub struct FlagResponse {
255 pub flags: i32,
257 }
258
259 pub struct MutualResponse {
261 pub users: Vec<String>,
263 pub servers: Vec<String>,
265 pub channels: Vec<String>,
267 }
268
269 pub struct BotInformation {
271 #[cfg_attr(feature = "serde", serde(rename = "owner"))]
273 pub owner_id: String,
274 }
275
276 pub struct DataSendFriendRequest {
278 pub username: String,
280 }
281);
282
283auto_derived_partial!(
284 pub struct UserVoiceState {
286 pub id: String,
287 pub joined_at: Timestamp,
288 pub is_receiving: bool,
289 pub is_publishing: bool,
290 pub screensharing: bool,
291 pub camera: bool,
292 },
293 "PartialUserVoiceState"
294);
295
296pub trait CheckRelationship {
297 fn with(&self, user: &str) -> RelationshipStatus;
298}
299
300impl CheckRelationship for Vec<Relationship> {
301 fn with(&self, user: &str) -> RelationshipStatus {
302 for entry in self {
303 if entry.user_id == user {
304 return entry.status.clone();
305 }
306 }
307
308 RelationshipStatus::None
309 }
310}