Skip to main content

stoat/ext/
user.rs

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