Skip to main content

twilight_http/request/channel/thread/create_forum_thread/
mod.rs

1mod message;
2
3pub use self::message::CreateForumThreadMessage;
4
5use self::message::CreateForumThreadMessageFields;
6
7#[cfg(not(target_os = "wasi"))]
8use crate::response::ResponseFuture;
9use crate::{
10    client::Client,
11    error::Error,
12    request::{Nullable, Request, attachment::AttachmentManager},
13    routing::Route,
14};
15use serde::{Deserialize, Serialize};
16use twilight_model::{
17    channel::{Channel, Message, thread::AutoArchiveDuration},
18    id::{
19        Id,
20        marker::{ChannelMarker, TagMarker},
21    },
22};
23
24#[derive(Deserialize, Serialize)]
25pub struct ForumThread {
26    #[serde(flatten)]
27    pub channel: Channel,
28    pub message: Message,
29}
30
31#[derive(Serialize)]
32struct CreateForumThreadFields<'a> {
33    #[serde(skip_serializing_if = "Option::is_none")]
34    applied_tags: Option<&'a [Id<TagMarker>]>,
35    #[serde(skip_serializing_if = "Option::is_none")]
36    auto_archive_duration: Option<AutoArchiveDuration>,
37    message: CreateForumThreadMessageFields<'a>,
38    name: &'a str,
39    #[serde(skip_serializing_if = "Option::is_none")]
40    rate_limit_per_user: Option<u16>,
41}
42
43/// Creates a new thread in a forum channel.
44///
45/// Requires the [`SEND_MESSAGES`] permission.
46///
47/// [`SEND_MESSAGES`]: twilight_model::guild::Permissions::SEND_MESSAGES
48#[must_use = "requests must be configured and executed"]
49pub struct CreateForumThread<'a> {
50    attachment_manager: AttachmentManager<'a>,
51    channel_id: Id<ChannelMarker>,
52    fields: CreateForumThreadFields<'a>,
53    http: &'a Client,
54}
55
56impl<'a> CreateForumThread<'a> {
57    pub(crate) const fn new(
58        http: &'a Client,
59        channel_id: Id<ChannelMarker>,
60        name: &'a str,
61    ) -> Self {
62        Self {
63            attachment_manager: AttachmentManager::new(),
64            channel_id,
65            fields: CreateForumThreadFields {
66                applied_tags: None,
67                auto_archive_duration: None,
68                message: CreateForumThreadMessageFields {
69                    allowed_mentions: None,
70                    attachments: None,
71                    components: None,
72                    content: None,
73                    embeds: None,
74                    flags: None,
75                    payload_json: None,
76                    sticker_ids: None,
77                },
78                name,
79                rate_limit_per_user: None,
80            },
81            http,
82        }
83    }
84
85    /// Set the forum thread's applied tags.
86    pub const fn applied_tags(mut self, applied_tags: &'a [Id<TagMarker>]) -> Self {
87        self.fields.applied_tags = Some(applied_tags);
88
89        self
90    }
91
92    /// Set the default auto archive duration for newly created threads in the
93    /// channel.
94    ///
95    /// Automatic archive durations are not locked behind the guild's boost
96    /// level.
97    pub const fn auto_archive_duration(
98        mut self,
99        auto_archive_duration: AutoArchiveDuration,
100    ) -> Self {
101        self.fields.auto_archive_duration = Some(auto_archive_duration);
102
103        self
104    }
105
106    pub const fn message(self) -> CreateForumThreadMessage<'a> {
107        CreateForumThreadMessage::new(self)
108    }
109
110    /// Execute the request, returning a future resolving to a [`Response`].
111    ///
112    /// [`Response`]: crate::response::Response
113    #[cfg(not(target_os = "wasi"))]
114    fn exec(self) -> ResponseFuture<ForumThread> {
115        let http = self.http;
116
117        match self.try_into_request() {
118            Ok(request) => http.request(request),
119            Err(source) => ResponseFuture::error(source),
120        }
121    }
122
123    fn try_into_request(mut self) -> Result<Request, Error> {
124        let mut request = Request::builder(&Route::CreateForumThread {
125            channel_id: self.channel_id.get(),
126        });
127
128        // Set the default allowed mentions if required.
129        if self.fields.message.allowed_mentions.is_none()
130            && let Some(allowed_mentions) = self.http.default_allowed_mentions()
131        {
132            self.fields.message.allowed_mentions = Some(Nullable(Some(allowed_mentions)));
133        }
134
135        // Determine whether we need to use a multipart/form-data body or a JSON
136        // body.
137        if !self.attachment_manager.is_empty() {
138            let form = if let Some(payload_json) = self.fields.message.payload_json {
139                self.attachment_manager.build_form(payload_json)
140            } else {
141                self.fields.message.attachments =
142                    Some(self.attachment_manager.get_partial_attachments());
143
144                let fields = crate::json::to_vec(&self.fields).map_err(Error::json)?;
145
146                self.attachment_manager.build_form(fields.as_ref())
147            };
148
149            request = request.form(form);
150        } else if let Some(payload_json) = self.fields.message.payload_json {
151            request = request.body(payload_json.to_vec());
152        } else {
153            request = request.json(&self.fields);
154        }
155
156        request.build()
157    }
158}