Skip to main content

twilight_http/request/channel/thread/
create_thread_from_message.rs

1use crate::{
2    client::Client,
3    error::Error,
4    request::{self, AuditLogReason, Request, TryIntoRequest},
5    response::{Response, ResponseFuture},
6    routing::Route,
7};
8use serde::Serialize;
9use std::future::IntoFuture;
10use twilight_model::{
11    channel::{Channel, thread::AutoArchiveDuration},
12    id::{
13        Id,
14        marker::{ChannelMarker, MessageMarker},
15    },
16};
17use twilight_validate::{
18    channel::{ChannelValidationError, name as validate_name},
19    request::{ValidationError, audit_reason as validate_audit_reason},
20};
21
22#[derive(Serialize)]
23struct CreateThreadFromMessageFields<'a> {
24    #[serde(skip_serializing_if = "Option::is_none")]
25    auto_archive_duration: Option<AutoArchiveDuration>,
26    name: &'a str,
27}
28
29/// Create a new thread from an existing message.
30///
31/// When called on a [`GuildText`] channel, this creates a
32/// [`PublicThread`].
33///
34/// When called on a [`GuildAnnouncement`] channel, this creates a [`AnnouncementThread`].
35///
36/// This request does not work when called on a [`GuildForum`] channel.
37///
38/// Automatic archive durations are not locked behind the guild's boost level.
39///
40/// The thread's ID will be the same as its parent message. This ensures only
41/// one thread can be created per message.
42///
43/// [`AnnouncementThread`]: twilight_model::channel::ChannelType::AnnouncementThread
44/// [`GuildAnnouncement`]: twilight_model::channel::ChannelType::GuildAnnouncement
45/// [`GuildForum`]: twilight_model::channel::ChannelType::GuildForum
46/// [`GuildText`]: twilight_model::channel::ChannelType::GuildText
47/// [`PublicThread`]: twilight_model::channel::ChannelType::PublicThread
48#[must_use = "requests must be configured and executed"]
49pub struct CreateThreadFromMessage<'a> {
50    channel_id: Id<ChannelMarker>,
51    fields: Result<CreateThreadFromMessageFields<'a>, ChannelValidationError>,
52    http: &'a Client,
53    message_id: Id<MessageMarker>,
54    reason: Result<Option<&'a str>, ValidationError>,
55}
56
57impl<'a> CreateThreadFromMessage<'a> {
58    pub(crate) fn new(
59        http: &'a Client,
60        channel_id: Id<ChannelMarker>,
61        message_id: Id<MessageMarker>,
62        name: &'a str,
63    ) -> Self {
64        let fields = Ok(CreateThreadFromMessageFields {
65            auto_archive_duration: None,
66            name,
67        })
68        .and_then(|fields| {
69            validate_name(name)?;
70
71            Ok(fields)
72        });
73
74        Self {
75            channel_id,
76            fields,
77            http,
78            message_id,
79            reason: Ok(None),
80        }
81    }
82
83    /// Set the thread's auto archive duration.
84    ///
85    /// Automatic archive durations are not locked behind the guild's boost
86    /// level.
87    pub const fn auto_archive_duration(
88        mut self,
89        auto_archive_duration: AutoArchiveDuration,
90    ) -> Self {
91        if let Ok(fields) = self.fields.as_mut() {
92            fields.auto_archive_duration = Some(auto_archive_duration);
93        }
94
95        self
96    }
97}
98
99impl<'a> AuditLogReason<'a> for CreateThreadFromMessage<'a> {
100    fn reason(mut self, reason: &'a str) -> Self {
101        self.reason = validate_audit_reason(reason).and(Ok(Some(reason)));
102
103        self
104    }
105}
106
107impl IntoFuture for CreateThreadFromMessage<'_> {
108    type Output = Result<Response<Channel>, Error>;
109
110    type IntoFuture = ResponseFuture<Channel>;
111
112    fn into_future(self) -> Self::IntoFuture {
113        let http = self.http;
114
115        match self.try_into_request() {
116            Ok(request) => http.request(request),
117            Err(source) => ResponseFuture::error(source),
118        }
119    }
120}
121
122impl TryIntoRequest for CreateThreadFromMessage<'_> {
123    fn try_into_request(self) -> Result<Request, Error> {
124        let fields = self.fields.map_err(Error::validation)?;
125
126        let mut request = Request::builder(&Route::CreateThreadFromMessage {
127            channel_id: self.channel_id.get(),
128            message_id: self.message_id.get(),
129        })
130        .json(&fields);
131
132        if let Some(reason) = self.reason.map_err(Error::validation)? {
133            request = request.headers(request::audit_header(reason)?);
134        }
135
136        request.build()
137    }
138}