twilight_http/request/guild/
update_current_member.rs

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