1use std::time::SystemTime;
2
3use async_trait::async_trait;
4use bytes::Bytes;
5use stoat_models::v0::{
6 DataEditUser, FlagResponse, MutualResponse, User, UserProfile, UserVoiceState,
7};
8
9use crate::{
10 GlobalCache, HttpClient, Identifiable, Result, builders::SendMessageBuilder, created_at,
11};
12
13#[async_trait]
14pub trait UserExt {
15 fn mention(&self) -> String;
16 fn name(&self) -> &str;
17
18 fn voice(&self, cache: impl AsRef<GlobalCache>) -> Vec<(String, UserVoiceState)>;
19
20 async fn send(&self, http: impl AsRef<HttpClient> + Send) -> Result<SendMessageBuilder>;
21 async fn edit(
22 &mut self,
23 http: impl AsRef<HttpClient> + Send,
24 data: &DataEditUser,
25 ) -> Result<()>;
26 async fn fetch_profile(&self, http: impl AsRef<HttpClient> + Send) -> Result<UserProfile>;
27 async fn fetch_flags(&self, http: impl AsRef<HttpClient> + Send) -> Result<FlagResponse>;
28 async fn fetch_mutuals(&self, http: impl AsRef<HttpClient> + Send) -> Result<MutualResponse>;
29 async fn fetch_default_avatar(&self, http: impl AsRef<HttpClient> + Send) -> Result<Bytes>;
30}
31
32#[async_trait]
33impl UserExt for User {
34 fn mention(&self) -> String {
35 format!("<@{}>", &self.id)
36 }
37
38 fn name(&self) -> &str {
39 self.display_name.as_deref().unwrap_or(&self.username)
40 }
41
42 fn voice(&self, cache: impl AsRef<GlobalCache>) -> Vec<(String, UserVoiceState)> {
43 let mut states = Vec::new();
44
45 cache.as_ref().servers.iter_sync(|_, server| {
46 for channel in &server.channels {
47 if let Some(channel_voice_state) = cache.as_ref().voice_states.get_sync(channel) {
48 if let Some(user_voice_state) = channel_voice_state
49 .participants
50 .iter()
51 .find(|s| &s.id == &self.id)
52 {
53 states.push((channel.clone(), user_voice_state.clone()));
54 }
55 }
56 }
57
58 true
59 });
60
61 states
62 }
63
64 async fn send(&self, http: impl AsRef<HttpClient> + Send) -> Result<SendMessageBuilder> {
65 let dm_channel = http.as_ref().open_dm(&self.id).await?;
66
67 Ok(SendMessageBuilder::new(
68 http.as_ref().clone(),
69 dm_channel.id().to_string(),
70 ))
71 }
72
73 async fn edit(
74 &mut self,
75 http: impl AsRef<HttpClient> + Send,
76 data: &DataEditUser,
77 ) -> Result<()> {
78 let user = http.as_ref().edit_user(&self.id, data).await?;
79
80 *self = user;
81
82 Ok(())
83 }
84
85 async fn fetch_profile(&self, http: impl AsRef<HttpClient> + Send) -> Result<UserProfile> {
86 http.as_ref().fetch_user_profile(&self.id).await
87 }
88
89 async fn fetch_flags(&self, http: impl AsRef<HttpClient> + Send) -> Result<FlagResponse> {
90 http.as_ref().fetch_user_flags(&self.id).await
91 }
92
93 async fn fetch_mutuals(&self, http: impl AsRef<HttpClient> + Send) -> Result<MutualResponse> {
94 http.as_ref().fetch_user_mutuals(&self.id).await
95 }
96
97 async fn fetch_default_avatar(&self, http: impl AsRef<HttpClient> + Send) -> Result<Bytes> {
98 http.as_ref().fetch_default_avatar(&self.id).await
99 }
100}
101
102impl Identifiable for User {
103 fn created_at(&self) -> SystemTime {
104 created_at(&self.id)
105 }
106}