Skip to main content

twilight_http/request/guild/member/
add_guild_member.rs

1#[cfg(not(target_os = "wasi"))]
2use crate::response::{Response, ResponseFuture};
3use crate::{
4    client::Client,
5    error::Error,
6    request::{Request, TryIntoRequest},
7    routing::Route,
8};
9use serde::Serialize;
10use std::future::IntoFuture;
11use twilight_model::{
12    guild::PartialMember,
13    id::{
14        Id,
15        marker::{GuildMarker, RoleMarker, UserMarker},
16    },
17};
18use twilight_validate::request::{ValidationError, nickname as validate_nickname};
19
20#[derive(Serialize)]
21struct AddGuildMemberFields<'a> {
22    pub access_token: &'a str,
23    #[serde(skip_serializing_if = "Option::is_none")]
24    pub deaf: Option<bool>,
25    #[serde(skip_serializing_if = "Option::is_none")]
26    pub mute: Option<bool>,
27    #[serde(skip_serializing_if = "Option::is_none")]
28    pub nick: Option<&'a str>,
29    #[serde(skip_serializing_if = "Option::is_none")]
30    pub roles: Option<&'a [Id<RoleMarker>]>,
31}
32
33#[must_use = "requests must be configured and executed"]
34pub struct AddGuildMember<'a> {
35    fields: Result<AddGuildMemberFields<'a>, ValidationError>,
36    guild_id: Id<GuildMarker>,
37    http: &'a Client,
38    user_id: Id<UserMarker>,
39}
40
41/// Add a user to a guild.
42///
43/// An access token for the user with `guilds.join` scope is required. All other
44/// fields are optional. See [Discord Docs/Add Guild Member].
45///
46/// [Discord Docs/Add Guild Member]: https://discord.com/developers/docs/resources/guild#add-guild-member
47impl<'a> AddGuildMember<'a> {
48    pub(crate) const fn new(
49        http: &'a Client,
50        guild_id: Id<GuildMarker>,
51        user_id: Id<UserMarker>,
52        access_token: &'a str,
53    ) -> Self {
54        Self {
55            fields: Ok(AddGuildMemberFields {
56                access_token,
57                deaf: None,
58                mute: None,
59                nick: None,
60                roles: None,
61            }),
62            guild_id,
63            http,
64            user_id,
65        }
66    }
67
68    /// Whether the new member will be unable to hear audio when connected to a
69    /// voice channel.
70    pub const fn deaf(mut self, deaf: bool) -> Self {
71        if let Ok(fields) = self.fields.as_mut() {
72            fields.deaf = Some(deaf);
73        }
74
75        self
76    }
77
78    /// Whether the new member will be unable to speak in voice channels.
79    pub const fn mute(mut self, mute: bool) -> Self {
80        if let Ok(fields) = self.fields.as_mut() {
81            fields.mute = Some(mute);
82        }
83
84        self
85    }
86
87    /// Set the user's initial nickname.
88    ///
89    /// The minimum length is 1 UTF-16 character and the maximum is 32 UTF-16
90    /// characters.
91    ///
92    /// # Errors
93    ///
94    /// Returns an error of type [`Nickname`] if the nickname length is too
95    /// short or too long.
96    ///
97    /// [`Nickname`]: twilight_validate::request::ValidationErrorType::Nickname
98    pub fn nick(mut self, nick: &'a str) -> Self {
99        self.fields = self.fields.and_then(|mut fields| {
100            validate_nickname(nick)?;
101
102            fields.nick.replace(nick);
103
104            Ok(fields)
105        });
106
107        self
108    }
109
110    /// List of roles to assign the new member.
111    pub const fn roles(mut self, roles: &'a [Id<RoleMarker>]) -> Self {
112        if let Ok(fields) = self.fields.as_mut() {
113            fields.roles = Some(roles);
114        }
115
116        self
117    }
118}
119
120#[cfg(not(target_os = "wasi"))]
121impl IntoFuture for AddGuildMember<'_> {
122    type Output = Result<Response<PartialMember>, Error>;
123
124    type IntoFuture = ResponseFuture<PartialMember>;
125
126    fn into_future(self) -> Self::IntoFuture {
127        let http = self.http;
128
129        match self.try_into_request() {
130            Ok(request) => http.request(request),
131            Err(source) => ResponseFuture::error(source),
132        }
133    }
134}
135
136impl TryIntoRequest for AddGuildMember<'_> {
137    fn try_into_request(self) -> Result<Request, Error> {
138        let fields = self.fields.map_err(Error::validation)?;
139
140        Request::builder(&Route::AddGuildMember {
141            guild_id: self.guild_id.get(),
142            user_id: self.user_id.get(),
143        })
144        .json(&fields)
145        .build()
146    }
147}