1use async_trait::async_trait;
2use stoat_models::v0::{Channel, DataBanCreate, DataMemberEdit, Member, Role, ServerBan, UserVoiceState};
3
4use crate::{GlobalCache, HttpClient, Identifiable, Result, builders::EditMemberBuilder};
5
6#[async_trait]
7pub trait MemberExt {
8 async fn ban(
10 &self,
11 http: impl AsRef<HttpClient> + Send,
12 reason: Option<String>,
13 ) -> Result<ServerBan>;
14
15 fn edit(&self, http: impl AsRef<HttpClient>) -> EditMemberBuilder;
17
18 async fn kick(&self, http: impl AsRef<HttpClient> + Send) -> Result<()>;
20
21 async fn add_roles(
23 &self,
24 http: impl AsRef<HttpClient> + Send,
25 roles: &[Role],
26 ) -> Result<Member>;
27
28 fn voice(&self, cache: impl AsRef<GlobalCache>) -> Option<(Channel, UserVoiceState)>;
30
31 fn mention(&self) -> String;
34}
35
36#[async_trait]
37impl MemberExt for Member {
38 async fn ban(
39 &self,
40 http: impl AsRef<HttpClient> + Send,
41 reason: Option<String>,
42 ) -> Result<ServerBan> {
43 http.as_ref()
44 .ban_member(&self.id.server, &self.id.user, &DataBanCreate { reason })
45 .await
46 }
47
48 fn edit(&self, http: impl AsRef<HttpClient>) -> EditMemberBuilder {
49 EditMemberBuilder::new(
50 http.as_ref().clone(),
51 self.id.server.clone(),
52 self.id.user.clone(),
53 )
54 }
55
56 async fn kick(&self, http: impl AsRef<HttpClient> + Send) -> Result<()> {
57 http.as_ref()
58 .kick_member(&self.id.server, &self.id.user)
59 .await
60 }
61
62 async fn add_roles(
63 &self,
64 http: impl AsRef<HttpClient> + Send,
65 roles: &[Role],
66 ) -> Result<Member> {
67 let mut new_roles = self.roles.clone();
68 new_roles.extend(roles.iter().map(|r| r.id.clone()));
69
70 http.as_ref()
71 .edit_member(
72 &self.id.server,
73 &self.id.user,
74 &DataMemberEdit {
75 nickname: None,
76 avatar: None,
77 roles: Some(new_roles),
78 timeout: None,
79 can_publish: None,
80 can_receive: None,
81 voice_channel: None,
82 remove: Vec::new(),
83 },
84 )
85 .await
86 }
87
88 fn voice(&self, cache: impl AsRef<GlobalCache>) -> Option<(Channel, UserVoiceState)> {
89 let server_channels = cache
90 .as_ref()
91 .servers
92 .get_sync(&self.id.server)
93 .map(|s| s.channels.clone())?;
94
95 for channel_id in server_channels {
96 if let Some(channel_voice_state) = cache.as_ref().voice_states.get_sync(&channel_id) {
97 if let Some(user_voice_state) = channel_voice_state
98 .participants
99 .iter()
100 .find(|s| &s.id == &self.id.user)
101 {
102 if let Some(channel) = cache.as_ref().get_channel(&channel_id) {
103 return Some((channel, user_voice_state.clone()));
104 }
105 }
106 }
107 }
108
109 None
110 }
111
112 fn mention(&self) -> String {
113 format!("<@{}>", &self.id.user)
114 }
115}
116
117impl Identifiable for Member {
118 fn id(&self) -> &str {
119 &self.id.user
120 }
121}