1use crate::snowflake::Snowflake;
2use crate::TitanString;
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Deserialize, Serialize)]
7pub struct User<'a> {
8 pub id: Snowflake,
10 pub username: TitanString<'a>,
12 pub discriminator: TitanString<'a>,
14 #[serde(default)]
16 pub global_name: Option<TitanString<'a>>,
17 #[serde(default)]
19 pub avatar: Option<TitanString<'a>>,
20 #[serde(default)]
22 pub bot: bool,
23 #[serde(default)]
25 pub system: bool,
26 #[serde(default)]
28 pub mfa_enabled: Option<bool>,
29 #[serde(default)]
31 pub banner: Option<TitanString<'a>>,
32 #[serde(default)]
34 pub accent_color: Option<u32>,
35 #[serde(default)]
37 pub locale: Option<TitanString<'a>>,
38 #[serde(default)]
40 pub verified: Option<bool>,
41 #[serde(default)]
43 pub email: Option<TitanString<'a>>,
44 #[serde(default)]
46 pub flags: Option<u64>,
47 #[serde(default)]
49 pub premium_type: Option<u8>,
50 #[serde(default)]
52 pub public_flags: Option<u64>,
53 #[serde(default)]
55 pub avatar_decoration_data: Option<crate::json::Value>,
56}
57
58impl User<'_> {
59 #[must_use]
61 pub fn avatar_url(&self) -> Option<String> {
62 self.avatar.as_ref().map(|hash| {
63 let ext = if hash.starts_with("a_") { "gif" } else { "png" };
64 format!(
65 "https://cdn.discordapp.com/avatars/{}/{}.{}",
66 self.id, hash, ext
67 )
68 })
69 }
70
71 #[must_use]
73 pub fn default_avatar_url(&self) -> String {
74 let index = if self.discriminator == "0" {
75 (self.id.0 >> 22) % 6
76 } else {
77 self.discriminator.parse::<u64>().unwrap_or(0) % 5
78 };
79 format!("https://cdn.discordapp.com/embed/avatars/{index}.png")
80 }
81
82 #[must_use]
84 pub fn face(&self) -> String {
85 self.avatar_url()
86 .unwrap_or_else(|| self.default_avatar_url())
87 }
88}
89
90impl crate::Mention for User<'_> {
91 fn mention(&self) -> String {
92 format!("<@{}>", self.id.0)
93 }
94}
95
96#[derive(Debug, Clone, Deserialize, Serialize)]
98pub struct PartialUser {
99 pub id: Snowflake,
100}
101
102#[derive(Debug, Clone, Deserialize, Serialize)]
104pub struct ClientStatus {
105 #[serde(default)]
106 pub desktop: Option<String>,
107 #[serde(default)]
108 pub mobile: Option<String>,
109 #[serde(default)]
110 pub web: Option<String>,
111}
112
113#[derive(Debug, Clone, Deserialize, Serialize)]
115pub struct PresenceUpdateEvent {
116 pub user: PartialUser,
117 #[serde(default)]
118 pub guild_id: Option<Snowflake>,
119 pub status: String,
120 #[serde(default)]
121 pub activities: Vec<crate::json::Value>,
122 #[serde(default)]
123 pub client_status: Option<ClientStatus>,
124}