serenity/builder/
edit_channel.rs

1#[cfg(feature = "http")]
2use super::Builder;
3use super::CreateForumTag;
4#[cfg(feature = "http")]
5use crate::http::CacheHttp;
6#[cfg(feature = "http")]
7use crate::internal::prelude::*;
8use crate::model::prelude::*;
9
10/// A builder to edit a [`GuildChannel`] for use via [`GuildChannel::edit`].
11///
12/// [Discord docs](https://discord.com/developers/docs/resources/channel#modify-channel-json-params-guild-channel).
13///
14/// # Examples
15///
16/// Edit a channel, providing a new name and topic:
17///
18/// ```rust,no_run
19/// # use serenity::builder::EditChannel;
20/// # use serenity::http::Http;
21/// # use serenity::model::channel::GuildChannel;
22/// #
23/// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
24/// # let http: Http = unimplemented!();
25/// # let mut channel: GuildChannel = unimplemented!();
26/// let builder = EditChannel::new().name("new name").topic("a test topic");
27/// if let Err(why) = channel.edit(&http, builder).await {
28///     // properly handle the error
29/// }
30/// # Ok(())
31/// # }
32/// ```
33#[derive(Clone, Debug, Default, Serialize)]
34#[must_use]
35pub struct EditChannel<'a> {
36    #[serde(skip_serializing_if = "Option::is_none")]
37    name: Option<String>,
38    #[serde(skip_serializing_if = "Option::is_none")]
39    #[serde(rename = "type")]
40    kind: Option<ChannelType>,
41    #[serde(skip_serializing_if = "Option::is_none")]
42    position: Option<u16>,
43    #[serde(skip_serializing_if = "Option::is_none")]
44    topic: Option<String>,
45    #[serde(skip_serializing_if = "Option::is_none")]
46    nsfw: Option<bool>,
47    #[serde(skip_serializing_if = "Option::is_none")]
48    rate_limit_per_user: Option<u16>,
49    #[serde(skip_serializing_if = "Option::is_none")]
50    bitrate: Option<u32>,
51    #[serde(skip_serializing_if = "Option::is_none")]
52    user_limit: Option<u32>,
53    #[serde(skip_serializing_if = "Option::is_none")]
54    permission_overwrites: Option<Vec<PermissionOverwriteData>>,
55    #[serde(skip_serializing_if = "Option::is_none")]
56    parent_id: Option<Option<ChannelId>>,
57    #[serde(skip_serializing_if = "Option::is_none")]
58    rtc_region: Option<Option<String>>,
59    #[serde(skip_serializing_if = "Option::is_none")]
60    video_quality_mode: Option<VideoQualityMode>,
61    #[serde(skip_serializing_if = "Option::is_none")]
62    default_auto_archive_duration: Option<AutoArchiveDuration>,
63    #[serde(skip_serializing_if = "Option::is_none")]
64    flags: Option<ChannelFlags>,
65    #[serde(skip_serializing_if = "Option::is_none")]
66    available_tags: Option<Vec<CreateForumTag>>,
67    #[serde(skip_serializing_if = "Option::is_none")]
68    default_reaction_emoji: Option<Option<ForumEmoji>>,
69    #[serde(skip_serializing_if = "Option::is_none")]
70    default_thread_rate_limit_per_user: Option<u16>,
71    #[serde(skip_serializing_if = "Option::is_none")]
72    default_sort_order: Option<SortOrder>,
73    #[serde(skip_serializing_if = "Option::is_none")]
74    default_forum_layout: Option<ForumLayoutType>,
75    #[serde(skip_serializing_if = "Option::is_none")]
76    status: Option<String>,
77
78    #[serde(skip)]
79    audit_log_reason: Option<&'a str>,
80}
81
82impl<'a> EditChannel<'a> {
83    /// Equivalent to [`Self::default`].
84    pub fn new() -> Self {
85        Self::default()
86    }
87
88    /// The bitrate of the channel in bits.
89    ///
90    /// This is for [voice] channels only.
91    ///
92    /// [voice]: ChannelType::Voice
93    pub fn bitrate(mut self, bitrate: u32) -> Self {
94        self.bitrate = Some(bitrate);
95        self
96    }
97
98    /// The camera video quality mode of the channel.
99    ///
100    /// This is for [voice] channels only.
101    ///
102    /// [voice]: ChannelType::Voice
103    pub fn video_quality_mode(mut self, quality: VideoQualityMode) -> Self {
104        self.video_quality_mode = Some(quality);
105        self
106    }
107
108    /// The voice region of the channel. It is automatic when `None`.
109    ///
110    /// This is for [voice] channels only.
111    ///
112    /// [voice]: ChannelType::Voice
113    pub fn voice_region(mut self, id: Option<String>) -> Self {
114        self.rtc_region = Some(id);
115        self
116    }
117
118    /// The name of the channel.
119    ///
120    /// Must be between 2 and 100 characters long.
121    pub fn name(mut self, name: impl Into<String>) -> Self {
122        self.name = Some(name.into());
123        self
124    }
125
126    /// The position of the channel in the channel list.
127    pub fn position(mut self, position: u16) -> Self {
128        self.position = Some(position);
129        self
130    }
131
132    /// The topic of the channel. Can be empty.
133    ///
134    /// Must be between 0 and 1024 characters long.
135    ///
136    /// This is for [text] channels only.
137    ///
138    /// [text]: ChannelType::Text
139    pub fn topic(mut self, topic: impl Into<String>) -> Self {
140        self.topic = Some(topic.into());
141        self
142    }
143
144    /// The status of the voice channel. Can be empty.
145    ///
146    /// Must be between 0 and 1024 characters long.
147    ///
148    /// This is for [voice] channels only.
149    ///
150    /// [voice]: ChannelType::Voice
151    pub fn status(mut self, status: impl Into<String>) -> Self {
152        self.status = Some(status.into());
153        self
154    }
155
156    /// Is the channel inappropriate for work?
157    ///
158    /// This is for [text] channels only.
159    ///
160    /// [text]: ChannelType::Text
161    pub fn nsfw(mut self, nsfw: bool) -> Self {
162        self.nsfw = Some(nsfw);
163        self
164    }
165
166    /// The number of users that may be in the channel simultaneously.
167    ///
168    /// This is for [voice] channels only.
169    ///
170    /// [voice]: ChannelType::Voice
171    pub fn user_limit(mut self, user_limit: u32) -> Self {
172        self.user_limit = Some(user_limit);
173        self
174    }
175
176    /// The parent category of the channel.
177    ///
178    /// This is for [text] and [voice] channels only.
179    ///
180    /// [text]: ChannelType::Text
181    /// [voice]: ChannelType::Voice
182    #[inline]
183    pub fn category<C: Into<Option<ChannelId>>>(mut self, category: C) -> Self {
184        self.parent_id = Some(category.into());
185        self
186    }
187
188    /// How many seconds must a user wait before sending another message.
189    ///
190    /// Bots, or users with the [`MANAGE_MESSAGES`] and/or [`MANAGE_CHANNELS`] permissions are
191    /// exempt from this restriction.
192    ///
193    /// **Note**: Must be between 0 and 21600 seconds (360 minutes or 6 hours).
194    ///
195    /// [`MANAGE_MESSAGES`]: Permissions::MANAGE_MESSAGES
196    /// [`MANAGE_CHANNELS`]: Permissions::MANAGE_CHANNELS
197    #[doc(alias = "slowmode")]
198    pub fn rate_limit_per_user(mut self, seconds: u16) -> Self {
199        self.rate_limit_per_user = Some(seconds);
200        self
201    }
202
203    /// A set of overwrites defining what a user or a user carrying a certain role can or can't do.
204    ///
205    /// # Example
206    ///
207    /// Inheriting permissions from an existing channel:
208    ///
209    /// ```rust,no_run
210    /// # use serenity::builder::EditChannel;
211    /// # use serenity::http::Http;
212    /// # use serenity::model::channel::GuildChannel;
213    /// # use std::sync::Arc;
214    /// #
215    /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
216    /// # let http: Arc<Http> = unimplemented!();
217    /// # let mut channel: GuildChannel = unimplemented!();
218    /// use serenity::model::channel::{PermissionOverwrite, PermissionOverwriteType};
219    /// use serenity::model::id::UserId;
220    /// use serenity::model::permissions::Permissions;
221    ///
222    /// // Assuming a channel has already been bound.
223    /// let permissions = vec![PermissionOverwrite {
224    ///     allow: Permissions::VIEW_CHANNEL,
225    ///     deny: Permissions::SEND_TTS_MESSAGES,
226    ///     kind: PermissionOverwriteType::Member(UserId::new(1234)),
227    /// }];
228    ///
229    /// let builder = EditChannel::new().name("my_edited_cool_channel").permissions(permissions);
230    /// channel.edit(http, builder).await?;
231    /// # Ok(())
232    /// # }
233    /// ```
234    pub fn permissions(mut self, perms: impl IntoIterator<Item = PermissionOverwrite>) -> Self {
235        let overwrites = perms.into_iter().map(Into::into).collect::<Vec<_>>();
236
237        self.permission_overwrites = Some(overwrites);
238        self
239    }
240
241    /// If this is a forum channel, sets the tags that can be assigned to forum posts.
242    pub fn available_tags(mut self, tags: impl IntoIterator<Item = CreateForumTag>) -> Self {
243        self.available_tags = Some(tags.into_iter().collect());
244        self
245    }
246
247    /// Sets the request's audit log reason.
248    pub fn audit_log_reason(mut self, reason: &'a str) -> Self {
249        self.audit_log_reason = Some(reason);
250        self
251    }
252
253    /// The type of channel; only conversion between text and announcement is supported and only in
254    /// guilds with the "NEWS" feature
255    pub fn kind(mut self, kind: ChannelType) -> Self {
256        self.kind = Some(kind);
257        self
258    }
259
260    /// The default duration that the clients use (not the API) for newly created threads in the
261    /// channel, in minutes, to automatically archive the thread after recent activity
262    pub fn default_auto_archive_duration(
263        mut self,
264        default_auto_archive_duration: AutoArchiveDuration,
265    ) -> Self {
266        self.default_auto_archive_duration = Some(default_auto_archive_duration);
267        self
268    }
269
270    /// Channel flags combined as a bitfield. Currently only [`ChannelFlags::REQUIRE_TAG`] is
271    /// supported.
272    pub fn flags(mut self, flags: ChannelFlags) -> Self {
273        self.flags = Some(flags);
274        self
275    }
276
277    /// The emoji to show in the add reaction button on a thread in a forum channel
278    pub fn default_reaction_emoji(mut self, default_reaction_emoji: Option<ForumEmoji>) -> Self {
279        self.default_reaction_emoji = Some(default_reaction_emoji);
280        self
281    }
282
283    /// The initial rate_limit_per_user to set on newly created threads in a channel. This field is
284    /// copied to the thread at creation time and does not live update.
285    pub fn default_thread_rate_limit_per_user(
286        mut self,
287        default_thread_rate_limit_per_user: u16,
288    ) -> Self {
289        self.default_thread_rate_limit_per_user = Some(default_thread_rate_limit_per_user);
290        self
291    }
292
293    /// The default sort order type used to order posts in forum channels
294    pub fn default_sort_order(mut self, default_sort_order: SortOrder) -> Self {
295        self.default_sort_order = Some(default_sort_order);
296        self
297    }
298
299    /// The default forum layout type used to display posts in forum channels
300    pub fn default_forum_layout(mut self, default_forum_layout: ForumLayoutType) -> Self {
301        self.default_forum_layout = Some(default_forum_layout);
302        self
303    }
304}
305
306#[cfg(feature = "http")]
307#[async_trait::async_trait]
308impl Builder for EditChannel<'_> {
309    type Context<'ctx> = ChannelId;
310    type Built = GuildChannel;
311
312    /// Edits the channel's settings.
313    ///
314    /// **Note**: Requires the [Manage Channels] permission. Modifying permissions via
315    /// [`Self::permissions`] also requires the [Manage Roles] permission.
316    ///
317    /// # Errors
318    ///
319    /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`] if the current user
320    /// lacks permission. Otherwise returns [`Error::Http`], as well as if invalid data is given.
321    ///
322    /// [Manage Channels]: Permissions::MANAGE_CHANNELS
323    /// [Manage Roles]: Permissions::MANAGE_ROLES
324    async fn execute(
325        self,
326        cache_http: impl CacheHttp,
327        ctx: Self::Context<'_>,
328    ) -> Result<Self::Built> {
329        #[cfg(feature = "cache")]
330        {
331            if let Some(cache) = cache_http.cache() {
332                crate::utils::user_has_perms_cache(cache, ctx, Permissions::MANAGE_CHANNELS)?;
333                if self.permission_overwrites.is_some() {
334                    crate::utils::user_has_perms_cache(cache, ctx, Permissions::MANAGE_ROLES)?;
335                }
336            }
337        }
338
339        if let Some(status) = &self.status {
340            #[derive(Serialize)]
341            struct EditVoiceStatusBody<'a> {
342                status: &'a str,
343            }
344
345            cache_http
346                .http()
347                .edit_voice_status(
348                    ctx,
349                    &EditVoiceStatusBody {
350                        status: status.as_str(),
351                    },
352                    self.audit_log_reason,
353                )
354                .await?;
355        }
356
357        cache_http.http().edit_channel(ctx, &self, self.audit_log_reason).await
358    }
359}