Skip to main content

twilight_http/request/guild/
update_current_member.rs

1#[cfg(not(target_os = "wasi"))]
2use crate::response::{Response, ResponseFuture, marker::EmptyBody};
3use crate::{
4    client::Client,
5    error::Error,
6    request::{self, AuditLogReason, Nullable, Request, TryIntoRequest},
7    routing::Route,
8};
9use serde::Serialize;
10use std::future::IntoFuture;
11use twilight_model::id::{Id, marker::GuildMarker};
12use twilight_validate::request::{
13    ValidationError, audit_reason as validate_audit_reason, bio as validate_bio,
14    nickname as validate_nickname,
15};
16
17#[derive(Serialize)]
18struct UpdateCurrentMemberFields<'a> {
19    #[serde(skip_serializing_if = "Option::is_none")]
20    nick: Option<Nullable<&'a str>>,
21    #[serde(skip_serializing_if = "Option::is_none")]
22    banner: Option<Nullable<&'a str>>,
23    #[serde(skip_serializing_if = "Option::is_none")]
24    avatar: Option<Nullable<&'a str>>,
25    #[serde(skip_serializing_if = "Option::is_none")]
26    bio: Option<Nullable<&'a str>>,
27}
28
29/// Update the user's member in a guild.
30#[must_use = "requests must be configured and executed"]
31pub struct UpdateCurrentMember<'a> {
32    fields: Result<UpdateCurrentMemberFields<'a>, ValidationError>,
33    guild_id: Id<GuildMarker>,
34    http: &'a Client,
35    reason: Result<Option<&'a str>, ValidationError>,
36}
37
38impl<'a> UpdateCurrentMember<'a> {
39    pub(crate) const fn new(http: &'a Client, guild_id: Id<GuildMarker>) -> Self {
40        Self {
41            fields: Ok(UpdateCurrentMemberFields {
42                nick: None,
43                banner: None,
44                avatar: None,
45                bio: None,
46            }),
47            guild_id,
48            http,
49            reason: Ok(None),
50        }
51    }
52
53    /// Set the current member's nickname.
54    ///
55    /// Set to [`None`] to clear the nickname.
56    ///
57    /// The minimum length is 1 UTF-16 character and the maximum is 32 UTF-16 characters.
58    ///
59    /// # Errors
60    ///
61    /// Returns an error of type [`Nickname`] if the nickname length is too
62    /// short or too long.
63    ///
64    /// [`Nickname`]: twilight_validate::request::ValidationErrorType::Nickname
65    pub fn nick(mut self, nick: Option<&'a str>) -> Self {
66        self.fields = self.fields.and_then(|mut fields| {
67            if let Some(nick) = nick {
68                validate_nickname(nick)?;
69            }
70
71            fields.nick = Some(Nullable(nick));
72
73            Ok(fields)
74        });
75
76        self
77    }
78
79    /// Set the current member's banner.
80    ///
81    /// Set to [`None`] to clear the banner.
82    ///
83    /// Uses the [Image Data URI Scheme](https://discord.com/developers/docs/reference#image-data) for image data.
84    pub const fn banner(mut self, banner: Option<&'a str>) -> Self {
85        if let Ok(fields) = self.fields.as_mut() {
86            fields.banner = Some(Nullable(banner));
87        }
88
89        self
90    }
91
92    /// Set the current member's avatar.
93    ///
94    /// Set to [`None`] to clear the avatar.
95    ///
96    /// Uses the [Image Data URI Scheme](https://discord.com/developers/docs/reference#image-data) for image data.
97    pub const fn avatar(mut self, avatar: Option<&'a str>) -> Self {
98        if let Ok(fields) = self.fields.as_mut() {
99            fields.avatar = Some(Nullable(avatar));
100        }
101
102        self
103    }
104
105    /// Set the current member's bio.
106    ///
107    /// Set to [`None`] to clear the bio.
108    ///
109    /// The minimum length is 1 codepoint character and the maximum is 400 codepoint characters.
110    ///
111    /// # Errors
112    ///
113    /// Returns an error of type [`Bio`] if the bio length is too
114    /// short or too long.
115    ///
116    /// [`Bio`]: twilight_validate::request::ValidationErrorType::Bio
117    pub fn bio(mut self, bio: Option<&'a str>) -> Self {
118        self.fields = self.fields.and_then(|mut fields| {
119            if let Some(bio) = bio {
120                validate_bio(bio)?;
121            }
122
123            fields.bio = Some(Nullable(bio));
124
125            Ok(fields)
126        });
127        self
128    }
129}
130
131impl<'a> AuditLogReason<'a> for UpdateCurrentMember<'a> {
132    fn reason(mut self, reason: &'a str) -> Self {
133        self.reason = validate_audit_reason(reason).and(Ok(Some(reason)));
134
135        self
136    }
137}
138
139#[cfg(not(target_os = "wasi"))]
140impl IntoFuture for UpdateCurrentMember<'_> {
141    type Output = Result<Response<EmptyBody>, Error>;
142
143    type IntoFuture = ResponseFuture<EmptyBody>;
144
145    fn into_future(self) -> Self::IntoFuture {
146        let http = self.http;
147
148        match self.try_into_request() {
149            Ok(request) => http.request(request),
150            Err(source) => ResponseFuture::error(source),
151        }
152    }
153}
154
155impl TryIntoRequest for UpdateCurrentMember<'_> {
156    fn try_into_request(self) -> Result<Request, Error> {
157        let fields = self.fields.map_err(Error::validation)?;
158        let mut request = Request::builder(&Route::UpdateCurrentMember {
159            guild_id: self.guild_id.get(),
160        })
161        .json(&fields);
162
163        if let Some(reason) = self.reason.map_err(Error::validation)? {
164            request = request.headers(request::audit_header(reason)?);
165        }
166
167        request.build()
168    }
169}