1use once_cell::sync::Lazy;
2use regex::Regex;
3
4use super::File;
5
6#[cfg(feature = "validator")]
7use validator::Validate;
8
9pub static RE_USERNAME: Lazy<Regex> = Lazy::new(|| Regex::new(r"^(\p{L}|[\d_.-])+$").unwrap());
14
15pub static RE_DISPLAY_NAME: Lazy<Regex> = Lazy::new(|| Regex::new(r"^[^\u200B\n\r]+$").unwrap());
20
21auto_derived_partial!(
22 pub struct User {
24 #[cfg_attr(feature = "serde", serde(rename = "_id"))]
26 pub id: String,
27 pub username: String,
29 pub discriminator: String,
31 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
33 pub display_name: Option<String>,
34 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
35 pub avatar: Option<File>,
37 #[cfg_attr(
39 feature = "serde",
40 serde(skip_serializing_if = "Vec::is_empty", default)
41 )]
42 pub relations: Vec<Relationship>,
43
44 #[cfg_attr(
48 feature = "serde",
49 serde(skip_serializing_if = "crate::if_zero_u32", default)
50 )]
51 pub badges: u32,
52 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
54 pub status: Option<UserStatus>,
55
56 #[cfg_attr(
60 feature = "serde",
61 serde(skip_serializing_if = "crate::if_zero_u32", default)
62 )]
63 pub flags: u32,
64 #[cfg_attr(
66 feature = "serde",
67 serde(skip_serializing_if = "crate::if_false", default)
68 )]
69 pub privileged: bool,
70 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
72 pub bot: Option<BotInformation>,
73
74 pub relationship: RelationshipStatus,
76 pub online: bool,
78 },
79 "PartialUser"
80);
81
82auto_derived!(
83 pub enum FieldsUser {
85 Avatar,
86 StatusText,
87 StatusPresence,
88 ProfileContent,
89 ProfileBackground,
90 DisplayName,
91
92 Internal,
94 }
95
96 #[derive(Default)]
98 pub enum RelationshipStatus {
99 #[default]
101 None,
102 User,
104 Friend,
106 Outgoing,
108 Incoming,
110 Blocked,
112 BlockedOther,
114 }
115
116 pub struct Relationship {
118 #[cfg_attr(feature = "serde", serde(rename = "_id"))]
120 pub user_id: String,
121 pub status: RelationshipStatus,
123 }
124
125 pub enum Presence {
127 Online,
129 Idle,
131 Focus,
133 Busy,
135 Invisible,
137 }
138
139 #[derive(Default)]
141 #[cfg_attr(feature = "validator", derive(Validate))]
142 pub struct UserStatus {
143 #[validate(length(min = 0, max = 128))]
145 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
146 pub text: Option<String>,
147 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
149 pub presence: Option<Presence>,
150 }
151
152 #[derive(Default)]
154 #[cfg_attr(feature = "validator", derive(Validate))]
155 pub struct UserProfile {
156 #[validate(length(min = 0, max = 2000))]
158 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
159 pub content: Option<String>,
160 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
162 pub background: Option<File>,
163 }
164
165 #[repr(u32)]
167 pub enum UserBadges {
168 Developer = 1,
170 Translator = 2,
172 Supporter = 4,
174 ResponsibleDisclosure = 8,
176 Founder = 16,
178 PlatformModeration = 32,
180 ActiveSupporter = 64,
182 Paw = 128,
184 EarlyAdopter = 256,
186 ReservedRelevantJokeBadge1 = 512,
188 ReservedRelevantJokeBadge2 = 1024,
190 }
191
192 #[repr(u32)]
194 pub enum UserFlags {
195 SuspendedUntil = 1,
197 Deleted = 2,
199 Banned = 4,
201 Spam = 8,
203 }
204
205 #[cfg_attr(feature = "validator", derive(Validate))]
207 pub struct DataUserProfile {
208 #[cfg_attr(feature = "validator", validate(length(min = 0, max = 2000)))]
210 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
211 pub content: Option<String>,
212 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
214 #[cfg_attr(feature = "validator", validate(length(min = 1, max = 128)))]
215 pub background: Option<String>,
216 }
217
218 #[cfg_attr(feature = "validator", derive(Validate))]
220 pub struct DataEditUser {
221 #[cfg_attr(
223 feature = "validator",
224 validate(length(min = 2, max = 32), regex = "RE_DISPLAY_NAME")
225 )]
226 pub display_name: Option<String>,
227 #[cfg_attr(feature = "validator", validate(length(min = 1, max = 128)))]
229 pub avatar: Option<String>,
230
231 #[cfg_attr(feature = "validator", validate)]
233 pub status: Option<UserStatus>,
234 #[cfg_attr(feature = "validator", validate)]
238 pub profile: Option<DataUserProfile>,
239
240 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
242 pub badges: Option<i32>,
243 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
245 pub flags: Option<i32>,
246
247 #[cfg_attr(feature = "validator", validate(length(min = 1)))]
249 pub remove: Option<Vec<FieldsUser>>,
250 }
251
252 pub struct FlagResponse {
254 pub flags: i32,
256 }
257
258 pub struct MutualResponse {
260 pub users: Vec<String>,
262 pub servers: Vec<String>,
264 }
265
266 pub struct BotInformation {
268 #[cfg_attr(feature = "serde", serde(rename = "owner"))]
270 pub owner_id: String,
271 }
272
273 pub struct DataSendFriendRequest {
275 pub username: String,
277 }
278);
279
280pub trait CheckRelationship {
281 fn with(&self, user: &str) -> RelationshipStatus;
282}
283
284impl CheckRelationship for Vec<Relationship> {
285 fn with(&self, user: &str) -> RelationshipStatus {
286 for entry in self {
287 if entry.user_id == user {
288 return entry.status.clone();
289 }
290 }
291
292 RelationshipStatus::None
293 }
294}