twilight_http/request/channel/reaction/
get_reactions.rs

1use super::RequestReactionType;
2use crate::{
3    client::Client,
4    error::Error,
5    request::{Request, TryIntoRequest},
6    response::{marker::ListBody, Response, ResponseFuture},
7    routing::Route,
8};
9use std::future::IntoFuture;
10use twilight_model::{
11    channel::message::ReactionType,
12    id::{
13        marker::{ChannelMarker, MessageMarker, UserMarker},
14        Id,
15    },
16    user::User,
17};
18use twilight_validate::request::{
19    get_reactions_limit as validate_get_reactions_limit, ValidationError,
20};
21
22struct GetReactionsFields {
23    after: Option<Id<UserMarker>>,
24    limit: Option<u16>,
25    kind: Option<ReactionType>,
26}
27
28/// Get a list of users that reacted to a message with an `emoji`.
29///
30/// This endpoint is limited to 100 users maximum, so if a message has more than 100 reactions,
31/// requests must be chained until all reactions are retrieved.
32#[must_use = "requests must be configured and executed"]
33pub struct GetReactions<'a> {
34    channel_id: Id<ChannelMarker>,
35    emoji: &'a RequestReactionType<'a>,
36    fields: Result<GetReactionsFields, ValidationError>,
37    http: &'a Client,
38    message_id: Id<MessageMarker>,
39}
40
41impl<'a> GetReactions<'a> {
42    pub(crate) const fn new(
43        http: &'a Client,
44        channel_id: Id<ChannelMarker>,
45        message_id: Id<MessageMarker>,
46        emoji: &'a RequestReactionType<'a>,
47    ) -> Self {
48        Self {
49            channel_id,
50            emoji,
51            fields: Ok(GetReactionsFields {
52                after: None,
53                limit: None,
54                kind: None,
55            }),
56            http,
57            message_id,
58        }
59    }
60
61    /// Get users after this id.
62    pub fn after(mut self, after: Id<UserMarker>) -> Self {
63        if let Ok(fields) = self.fields.as_mut() {
64            fields.after = Some(after);
65        }
66
67        self
68    }
69
70    /// Set the maximum number of users to retrieve.
71    ///
72    /// The minimum is 1 and the maximum is 100. If no limit is specified, Discord sets the default
73    /// to 25.
74    ///
75    /// # Errors
76    ///
77    /// Returns an error of type [`GetReactions`] if the amount is greater than
78    /// 100.
79    ///
80    /// [`GetReactions`]: twilight_validate::request::ValidationErrorType::GetReactions
81    pub fn limit(mut self, limit: u16) -> Self {
82        self.fields = self.fields.and_then(|mut fields| {
83            validate_get_reactions_limit(limit)?;
84            fields.limit = Some(limit);
85
86            Ok(fields)
87        });
88
89        self
90    }
91
92    /// Set the kind of reaction to retrieve.
93    ///
94    /// This can be either a super reaction or a normal reaction.
95    pub fn kind(mut self, kind: ReactionType) -> Self {
96        if let Ok(fields) = self.fields.as_mut() {
97            fields.kind = Some(kind);
98        }
99
100        self
101    }
102}
103
104impl IntoFuture for GetReactions<'_> {
105    type Output = Result<Response<ListBody<User>>, Error>;
106
107    type IntoFuture = ResponseFuture<ListBody<User>>;
108
109    fn into_future(self) -> Self::IntoFuture {
110        let http = self.http;
111
112        match self.try_into_request() {
113            Ok(request) => http.request(request),
114            Err(source) => ResponseFuture::error(source),
115        }
116    }
117}
118
119impl TryIntoRequest for GetReactions<'_> {
120    fn try_into_request(self) -> Result<Request, Error> {
121        let fields = self.fields.map_err(Error::validation)?;
122
123        Ok(Request::from_route(&Route::GetReactionUsers {
124            after: fields.after.map(Id::get),
125            channel_id: self.channel_id.get(),
126            emoji: self.emoji,
127            limit: fields.limit,
128            message_id: self.message_id.get(),
129            kind: fields.kind.map(Into::into),
130        }))
131    }
132}