Skip to main content

stoat/ext/
member.rs

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}