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

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