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