serenity/model/guild/mod.rs
1//! Models relating to guilds and types that it owns.
2
3pub mod audit_log;
4pub mod automod;
5mod emoji;
6mod guild_id;
7mod guild_preview;
8mod integration;
9mod member;
10mod partial_guild;
11mod premium_tier;
12mod role;
13mod scheduled_event;
14mod system_channel;
15mod welcome_screen;
16
17#[cfg(feature = "model")]
18use std::borrow::Cow;
19
20#[cfg(feature = "model")]
21use tracing::{error, warn};
22
23pub use self::emoji::*;
24pub use self::guild_id::*;
25pub use self::guild_preview::*;
26pub use self::integration::*;
27pub use self::member::*;
28pub use self::partial_guild::*;
29pub use self::premium_tier::*;
30pub use self::role::*;
31pub use self::scheduled_event::*;
32pub use self::system_channel::*;
33pub use self::welcome_screen::*;
34#[cfg(feature = "model")]
35use crate::builder::{
36 AddMember,
37 CreateChannel,
38 CreateCommand,
39 CreateScheduledEvent,
40 CreateSoundboard,
41 CreateSticker,
42 EditAutoModRule,
43 EditCommandPermissions,
44 EditGuild,
45 EditGuildIncidentActions,
46 EditGuildWelcomeScreen,
47 EditGuildWidget,
48 EditMember,
49 EditRole,
50 EditScheduledEvent,
51 EditSoundboard,
52 EditSticker,
53};
54#[cfg(all(feature = "cache", feature = "model"))]
55use crate::cache::Cache;
56#[cfg(feature = "collector")]
57use crate::collector::{MessageCollector, ReactionCollector};
58#[cfg(feature = "model")]
59use crate::constants::LARGE_THRESHOLD;
60#[cfg(feature = "collector")]
61use crate::gateway::ShardMessenger;
62#[cfg(feature = "model")]
63use crate::http::{CacheHttp, Http, UserPagination};
64#[cfg(feature = "model")]
65use crate::json::json;
66use crate::model::prelude::*;
67use crate::model::utils::*;
68
69/// A representation of a banning of a user.
70///
71/// [Discord docs](https://discord.com/developers/docs/resources/guild#ban-object).
72#[derive(Clone, Debug, Eq, Hash, PartialEq, Deserialize, Serialize)]
73#[non_exhaustive]
74pub struct Ban {
75 /// The reason given for this ban.
76 pub reason: Option<String>,
77 /// The user that was banned.
78 pub user: User,
79}
80
81/// The response from [`GuildId::bulk_ban`].
82///
83/// [Discord docs](https://discord.com/developers/docs/resources/guild#bulk-guild-ban).
84#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
85#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
86#[non_exhaustive]
87pub struct BulkBanResponse {
88 /// The users that were successfully banned.
89 pub banned_users: Vec<UserId>,
90 /// The users that were not successfully banned.
91 pub failed_users: Vec<UserId>,
92}
93
94#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
95#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
96pub struct AfkMetadata {
97 /// Id of a voice channel that's considered the AFK channel.
98 pub afk_channel_id: ChannelId,
99 /// The amount of seconds a user can not show any activity in a voice channel before being
100 /// moved to an AFK channel -- if one exists.
101 pub afk_timeout: AfkTimeout,
102}
103
104/// Information about a Discord guild, such as channels, emojis, etc.
105///
106/// [Discord docs](https://discord.com/developers/docs/resources/guild#guild-object) plus
107/// [extension](https://discord.com/developers/docs/topics/gateway-events#guild-create).
108#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
109#[derive(Clone, Debug, Default, Deserialize, Serialize)]
110#[non_exhaustive]
111pub struct Guild {
112 /// The unique Id identifying the guild.
113 ///
114 /// This is equivalent to the Id of the default role (`@everyone`).
115 pub id: GuildId,
116 /// The name of the guild.
117 pub name: String,
118 /// The hash of the icon used by the guild.
119 ///
120 /// In the client, this appears on the guild list on the left-hand side.
121 pub icon: Option<ImageHash>,
122 /// Icon hash, returned when in the template object
123 pub icon_hash: Option<ImageHash>,
124 /// An identifying hash of the guild's splash icon.
125 ///
126 /// If the `InviteSplash` feature is enabled, this can be used to generate a URL to a splash
127 /// image.
128 pub splash: Option<ImageHash>,
129 /// An identifying hash of the guild discovery's splash icon.
130 ///
131 /// **Note**: Only present for guilds with the `DISCOVERABLE` feature.
132 pub discovery_splash: Option<ImageHash>,
133 // Omitted `owner` field because only Http::get_guilds uses it, which returns GuildInfo
134 /// The Id of the [`User`] who owns the guild.
135 pub owner_id: UserId,
136 // Omitted `permissions` field because only Http::get_guilds uses it, which returns GuildInfo
137 // Omitted `region` field because it is deprecated (see Discord docs)
138 /// Information about the voice afk channel.
139 #[serde(flatten)]
140 pub afk_metadata: Option<AfkMetadata>,
141 /// Whether or not the guild widget is enabled.
142 pub widget_enabled: Option<bool>,
143 /// The channel id that the widget will generate an invite to, or null if set to no invite
144 pub widget_channel_id: Option<ChannelId>,
145 /// Indicator of the current verification level of the guild.
146 pub verification_level: VerificationLevel,
147 /// Indicator of whether notifications for all messages are enabled by
148 /// default in the guild.
149 pub default_message_notifications: DefaultMessageNotificationLevel,
150 /// Default explicit content filter level.
151 pub explicit_content_filter: ExplicitContentFilter,
152 /// A mapping of the guild's roles.
153 #[serde(with = "roles")]
154 pub roles: HashMap<RoleId, Role>,
155 /// All of the guild's custom emojis.
156 #[serde(with = "emojis")]
157 pub emojis: HashMap<EmojiId, Emoji>,
158 /// The guild features. These are user-invisible options which are used for Discord rollouts
159 /// and/or paid benefits. More information is available at [`discord's documentation`].
160 ///
161 /// [`discord's documentation`]: https://discord.com/developers/docs/resources/guild#guild-object-guild-features
162 pub features: Vec<String>,
163 /// Indicator of whether the guild requires multi-factor authentication for [`Role`]s or
164 /// [`User`]s with moderation permissions.
165 pub mfa_level: MfaLevel,
166 /// Application ID of the guild creator if it is bot-created.
167 pub application_id: Option<ApplicationId>,
168 /// The ID of the channel to which system messages are sent.
169 pub system_channel_id: Option<ChannelId>,
170 /// System channel flags.
171 pub system_channel_flags: SystemChannelFlags,
172 /// The id of the channel where rules and/or guidelines are displayed.
173 ///
174 /// **Note**: Only available on `COMMUNITY` guild, see [`Self::features`].
175 pub rules_channel_id: Option<ChannelId>,
176 /// The maximum number of presences for the guild. The default value is currently 25000.
177 ///
178 /// **Note**: It is in effect when it is `None`.
179 pub max_presences: Option<u64>,
180 /// The maximum number of members for the guild.
181 pub max_members: Option<u64>,
182 /// The vanity url code for the guild, if it has one.
183 pub vanity_url_code: Option<String>,
184 /// The server's description, if it has one.
185 pub description: Option<String>,
186 /// The guild's banner, if it has one.
187 pub banner: Option<String>,
188 /// The server's premium boosting level.
189 pub premium_tier: PremiumTier,
190 /// The total number of users currently boosting this server.
191 pub premium_subscription_count: Option<u64>,
192 /// The preferred locale of this guild only set if guild has the "COMMUNITY" feature,
193 /// defaults to en-US.
194 pub preferred_locale: String,
195 /// The id of the channel where admins and moderators of Community guilds receive notices from
196 /// Discord.
197 ///
198 /// **Note**: Only available on `COMMUNITY` guild, see [`Self::features`].
199 pub public_updates_channel_id: Option<ChannelId>,
200 /// The maximum amount of users in a video channel.
201 pub max_video_channel_users: Option<u64>,
202 /// The maximum amount of users in a stage video channel
203 pub max_stage_video_channel_users: Option<u64>,
204 /// Approximate number of members in this guild.
205 pub approximate_member_count: Option<u64>,
206 /// Approximate number of non-offline members in this guild.
207 pub approximate_presence_count: Option<u64>,
208 /// The welcome screen of the guild.
209 ///
210 /// **Note**: Only available on `COMMUNITY` guild, see [`Self::features`].
211 pub welcome_screen: Option<GuildWelcomeScreen>,
212 /// The guild NSFW state. See [`discord support article`].
213 ///
214 /// [`discord support article`]: https://support.discord.com/hc/en-us/articles/1500005389362-NSFW-Server-Designation
215 pub nsfw_level: NsfwLevel,
216 /// All of the guild's custom stickers.
217 #[serde(with = "stickers")]
218 pub stickers: HashMap<StickerId, Sticker>,
219 /// Whether the guild has the boost progress bar enabled
220 pub premium_progress_bar_enabled: bool,
221
222 // =======
223 // From here on, all fields are from Guild Create Event's extra fields (see Discord docs)
224 // =======
225 /// The date that the current user joined the guild.
226 pub joined_at: Timestamp,
227 /// Indicator of whether the guild is considered "large" by Discord.
228 pub large: bool,
229 /// Whether this guild is unavailable due to an outage.
230 #[serde(default)]
231 pub unavailable: bool,
232 /// The number of members in the guild.
233 pub member_count: u64,
234 /// A mapping of [`User`]s to their current voice state.
235 #[serde(serialize_with = "serialize_map_values")]
236 #[serde(deserialize_with = "deserialize_voice_states")]
237 pub voice_states: HashMap<UserId, VoiceState>,
238 /// Users who are members of the guild.
239 ///
240 /// Members might not all be available when the [`ReadyEvent`] is received if the
241 /// [`Self::member_count`] is greater than the [`LARGE_THRESHOLD`] set by the library.
242 #[serde(with = "members")]
243 pub members: HashMap<UserId, Member>,
244 /// All voice and text channels contained within a guild.
245 ///
246 /// This contains all channels regardless of permissions (i.e. the ability of the bot to read
247 /// from or connect to them).
248 #[serde(serialize_with = "serialize_map_values")]
249 #[serde(deserialize_with = "deserialize_guild_channels")]
250 pub channels: HashMap<ChannelId, GuildChannel>,
251 /// All active threads in this guild that current user has permission to view.
252 ///
253 /// A thread is guaranteed (for errors, not for panics) to be cached if a `MESSAGE_CREATE`
254 /// event is fired in said thread, however an `INTERACTION_CREATE` may not have a private
255 /// thread in cache.
256 pub threads: Vec<GuildChannel>,
257 /// A mapping of [`User`]s' Ids to their current presences.
258 ///
259 /// **Note**: This will be empty unless the "guild presences" privileged intent is enabled.
260 #[serde(with = "presences")]
261 pub presences: HashMap<UserId, Presence>,
262 /// The stage instances in this guild.
263 pub stage_instances: Vec<StageInstance>,
264 /// The stage instances in this guild.
265 #[serde(rename = "guild_scheduled_events")]
266 pub scheduled_events: Vec<ScheduledEvent>,
267 /// The id of the channel where this guild will recieve safety alerts.
268 pub safety_alerts_channel_id: Option<ChannelId>,
269 /// The incidents data for this guild, if any.
270 pub incidents_data: Option<IncidentsData>,
271}
272
273#[cfg(feature = "model")]
274impl Guild {
275 /// Gets all auto moderation [`Rule`]s of this guild via HTTP.
276 ///
277 /// **Note**: Requires the [Manage Guild] permission.
278 ///
279 /// # Errors
280 ///
281 /// Returns an [`Error::Http`] if the guild is unavailable.
282 ///
283 /// [Manage Guild]: Permissions::MANAGE_GUILD
284 #[inline]
285 pub async fn automod_rules(&self, http: impl AsRef<Http>) -> Result<Vec<Rule>> {
286 self.id.automod_rules(http).await
287 }
288
289 /// Gets an auto moderation [`Rule`] of this guild by its ID via HTTP.
290 ///
291 /// **Note**: Requires the [Manage Guild] permission.
292 ///
293 /// # Errors
294 ///
295 /// Returns an [`Error::Http`] if a rule with the given ID does not exist.
296 ///
297 /// [Manage Guild]: Permissions::MANAGE_GUILD
298 #[inline]
299 pub async fn automod_rule(
300 &self,
301 http: impl AsRef<Http>,
302 rule_id: impl Into<RuleId>,
303 ) -> Result<Rule> {
304 self.id.automod_rule(http, rule_id).await
305 }
306
307 /// Creates an auto moderation [`Rule`] in the guild.
308 ///
309 /// **Note**: Requires the [Manage Guild] permission.
310 ///
311 /// # Examples
312 ///
313 /// See [`GuildId::create_automod_rule`] for details.
314 ///
315 /// # Errors
316 ///
317 /// Returns [`Error::Http`] if the current user lacks permission, or if invalid data is given.
318 ///
319 /// [Manage Guild]: Permissions::MANAGE_GUILD
320 #[inline]
321 pub async fn create_automod_rule(
322 &self,
323 cache_http: impl CacheHttp,
324 builder: EditAutoModRule<'_>,
325 ) -> Result<Rule> {
326 self.id.create_automod_rule(cache_http, builder).await
327 }
328
329 /// Edit an auto moderation [`Rule`], given its Id.
330 ///
331 /// **Note**: Requires the [Manage Guild] permission.
332 ///
333 /// # Errors
334 ///
335 /// Returns [`Error::Http`] if the current user lacks permission, or if invalid data is given.
336 ///
337 /// [Manage Guild]: Permissions::MANAGE_GUILD
338 #[inline]
339 pub async fn edit_automod_rule(
340 &self,
341 cache_http: impl CacheHttp,
342 rule_id: impl Into<RuleId>,
343 builder: EditAutoModRule<'_>,
344 ) -> Result<Rule> {
345 self.id.edit_automod_rule(cache_http, rule_id, builder).await
346 }
347
348 /// Deletes an auto moderation [`Rule`] from the guild.
349 ///
350 /// **Note**: Requires the [Manage Guild] permission.
351 ///
352 /// # Errors
353 ///
354 /// Returns [`Error::Http`] if the current user lacks permission, or if a rule with that Id
355 /// does not exist.
356 ///
357 /// [Manage Guild]: Permissions::MANAGE_GUILD
358 #[inline]
359 pub async fn delete_automod_rule(
360 &self,
361 http: impl AsRef<Http>,
362 rule_id: impl Into<RuleId>,
363 ) -> Result<()> {
364 self.id.delete_automod_rule(http, rule_id).await
365 }
366
367 #[cfg(feature = "cache")]
368 fn check_hierarchy(&self, cache: &Cache, other_user: UserId) -> Result<()> {
369 let current_id = cache.as_ref().current_user().id;
370
371 if let Some(higher) = self.greater_member_hierarchy(cache, other_user, current_id) {
372 if higher != current_id {
373 return Err(Error::Model(ModelError::Hierarchy));
374 }
375 }
376
377 Ok(())
378 }
379
380 /// Returns the "default" channel of the guild for the passed user id. (This returns the first
381 /// channel that can be read by the user, if there isn't one, returns [`None`])
382 #[must_use]
383 pub fn default_channel(&self, uid: UserId) -> Option<&GuildChannel> {
384 let member = self.members.get(&uid)?;
385 self.channels.values().find(|&channel| {
386 channel.kind != ChannelType::Category
387 && self.user_permissions_in(channel, member).view_channel()
388 })
389 }
390
391 /// Returns the guaranteed "default" channel of the guild. (This returns the first channel that
392 /// can be read by everyone, if there isn't one, returns [`None`])
393 ///
394 /// **Note**: This is very costly if used in a server with lots of channels, members, or both.
395 #[must_use]
396 pub fn default_channel_guaranteed(&self) -> Option<&GuildChannel> {
397 self.channels.values().find(|&channel| {
398 channel.kind != ChannelType::Category
399 && self
400 .members
401 .values()
402 .map(|member| self.user_permissions_in(channel, member))
403 .all(Permissions::view_channel)
404 })
405 }
406
407 /// Intentionally not async. Retrieving anything from HTTP here is overkill/undesired
408 #[cfg(feature = "cache")]
409 pub(crate) fn require_perms(
410 &self,
411 cache: &Cache,
412 required_permissions: Permissions,
413 ) -> Result<(), Error> {
414 if let Some(member) = self.members.get(&cache.current_user().id) {
415 // This isn't used for any channel-specific permissions, but sucks still.
416 #[allow(deprecated)]
417 let bot_permissions = self.member_permissions(member);
418 if !bot_permissions.contains(required_permissions) {
419 return Err(Error::Model(ModelError::InvalidPermissions {
420 required: required_permissions,
421 present: bot_permissions,
422 }));
423 }
424 }
425 Ok(())
426 }
427
428 #[cfg(feature = "cache")]
429 #[deprecated = "Iterate through Guild::channels and use Iterator::find"]
430 pub fn channel_id_from_name(
431 &self,
432 #[allow(unused_variables)] cache: impl AsRef<Cache>,
433 name: impl AsRef<str>,
434 ) -> Option<ChannelId> {
435 let name = name.as_ref();
436
437 self.channels.values().find(|c| c.name == name).map(|c| c.id)
438 }
439
440 /// Ban a [`User`] from the guild, deleting a number of days' worth of messages (`dmd`) between
441 /// the range 0 and 7.
442 ///
443 /// Refer to the documentation for [`Guild::ban`] for more information.
444 ///
445 /// **Note**: Requires the [Ban Members] permission.
446 ///
447 /// # Examples
448 ///
449 /// Ban a member and remove all messages they've sent in the last 4 days:
450 ///
451 /// ```rust,ignore
452 /// // assumes a `user` and `guild` have already been bound
453 /// let _ = guild.ban(user, 4);
454 /// ```
455 ///
456 /// # Errors
457 ///
458 /// Returns a [`ModelError::DeleteMessageDaysAmount`] if the number of days' worth of messages
459 /// to delete is over the maximum.
460 ///
461 /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`] if the current user
462 /// does not have permission to perform bans, or may return a [`ModelError::Hierarchy`] if the
463 /// member to be banned has a higher role than the current user.
464 ///
465 /// Otherwise returns [`Error::Http`] if the member cannot be banned.
466 ///
467 /// [Ban Members]: Permissions::BAN_MEMBERS
468 #[inline]
469 pub async fn ban(
470 &self,
471 cache_http: impl CacheHttp,
472 user: impl Into<UserId>,
473 dmd: u8,
474 ) -> Result<()> {
475 self.ban_with_reason_(cache_http, user.into(), dmd, "").await
476 }
477
478 /// Ban a [`User`] from the guild with a reason. Refer to [`Self::ban`] to further
479 /// documentation.
480 ///
481 /// # Errors
482 ///
483 /// In addition to the possible reasons [`Self::ban`] may return an error, an
484 /// [`Error::ExceededLimit`] may also be returned if the reason is too long.
485 #[inline]
486 pub async fn ban_with_reason(
487 &self,
488 cache_http: impl CacheHttp,
489 user: impl Into<UserId>,
490 dmd: u8,
491 reason: impl AsRef<str>,
492 ) -> Result<()> {
493 self.ban_with_reason_(cache_http, user.into(), dmd, reason.as_ref()).await
494 }
495
496 async fn ban_with_reason_(
497 &self,
498 cache_http: impl CacheHttp,
499 user: UserId,
500 dmd: u8,
501 reason: &str,
502 ) -> Result<()> {
503 #[cfg(feature = "cache")]
504 {
505 if let Some(cache) = cache_http.cache() {
506 self.require_perms(cache, Permissions::BAN_MEMBERS)?;
507
508 self.check_hierarchy(cache, user)?;
509 }
510 }
511
512 self.id.ban_with_reason(cache_http.http(), user, dmd, reason).await
513 }
514
515 /// Bans multiple users from the guild, returning the users that were and weren't banned.
516 ///
517 /// # Errors
518 ///
519 /// See [`GuildId::bulk_ban`] for more information.
520 pub async fn bulk_ban(
521 &self,
522 cache_http: impl CacheHttp,
523 user_ids: &[UserId],
524 delete_message_seconds: u32,
525 reason: Option<&str>,
526 ) -> Result<BulkBanResponse> {
527 #[cfg(feature = "cache")]
528 {
529 if let Some(cache) = cache_http.cache() {
530 self.require_perms(cache, Permissions::BAN_MEMBERS & Permissions::MANAGE_GUILD)?;
531 }
532 }
533
534 self.id.bulk_ban(cache_http.http(), user_ids, delete_message_seconds, reason).await
535 }
536
537 /// Returns the formatted URL of the guild's banner image, if one exists.
538 #[must_use]
539 pub fn banner_url(&self) -> Option<String> {
540 self.banner.as_ref().map(|banner| cdn!("/banners/{}/{}.webp?size=1024", self.id, banner))
541 }
542
543 /// Gets a list of the guild's bans, with additional options and filtering. See
544 /// [`Http::get_bans`] for details.
545 ///
546 /// **Note**: Requires the [Ban Members] permission.
547 ///
548 /// # Errors
549 ///
550 /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`] if the current user
551 /// does not have permission to perform bans.
552 ///
553 /// [Ban Members]: Permissions::BAN_MEMBERS
554 pub async fn bans(
555 &self,
556 cache_http: impl CacheHttp,
557 target: Option<UserPagination>,
558 limit: Option<u8>,
559 ) -> Result<Vec<Ban>> {
560 #[cfg(feature = "cache")]
561 {
562 if let Some(cache) = cache_http.cache() {
563 self.require_perms(cache, Permissions::BAN_MEMBERS)?;
564 }
565 }
566
567 self.id.bans(cache_http.http(), target, limit).await
568 }
569
570 /// Gets a user's ban from the guild.
571 /// See [`Http::get_bans`] for details.
572 ///
573 /// **Note**: Requires the [Ban Members] permission.
574 ///
575 /// # Errors
576 ///
577 /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`] if the current user
578 /// does not have permission to perform bans.
579 ///
580 /// [Ban Members]: Permissions::BAN_MEMBERS
581 pub async fn get_ban(
582 &self,
583 cache_http: impl CacheHttp,
584 user_id: UserId,
585 ) -> Result<Option<Ban>> {
586 #[cfg(feature = "cache")]
587 {
588 if let Some(cache) = cache_http.cache() {
589 self.require_perms(cache, Permissions::BAN_MEMBERS)?;
590 }
591 }
592
593 self.id.get_ban(cache_http.http(), user_id).await
594 }
595
596 /// Adds a [`User`] to this guild with a valid OAuth2 access token.
597 ///
598 /// Returns the created [`Member`] object, or nothing if the user is already a member of the
599 /// guild.
600 ///
601 /// # Errors
602 ///
603 /// Returns [`Error::Http`] if the current user lacks permission, or if invalid data is given.
604 #[inline]
605 pub async fn add_member(
606 &self,
607 cache_http: impl CacheHttp,
608 user_id: impl Into<UserId>,
609 builder: AddMember,
610 ) -> Result<Option<Member>> {
611 self.id.add_member(cache_http, user_id, builder).await
612 }
613
614 /// Retrieves a list of [`AuditLogs`] for the guild.
615 ///
616 /// **Note**: Requires the [View Audit Log] permission.
617 ///
618 /// # Errors
619 ///
620 /// Returns [`Error::Http`] if the current user does not have permission to view the audit log,
621 /// or if an invalid value is given.
622 ///
623 /// [View Audit Log]: Permissions::VIEW_AUDIT_LOG
624 #[inline]
625 pub async fn audit_logs(
626 &self,
627 http: impl AsRef<Http>,
628 action_type: Option<audit_log::Action>,
629 user_id: Option<UserId>,
630 before: Option<AuditLogEntryId>,
631 limit: Option<u8>,
632 ) -> Result<AuditLogs> {
633 self.id.audit_logs(http, action_type, user_id, before, limit).await
634 }
635
636 /// Gets all of the guild's channels over the REST API.
637 ///
638 /// # Errors
639 ///
640 /// Returns [`Error::Http`] if the guild is currently unavailable.
641 #[inline]
642 pub async fn channels(
643 &self,
644 http: impl AsRef<Http>,
645 ) -> Result<HashMap<ChannelId, GuildChannel>> {
646 self.id.channels(http).await
647 }
648
649 /// Creates a guild with the data provided.
650 ///
651 /// Only a [`PartialGuild`] will be immediately returned, and a full [`Guild`] will be received
652 /// over a [`Shard`].
653 ///
654 /// **Note**: This endpoint is usually only available for user accounts. Refer to Discord's
655 /// information for the endpoint [here][whitelist] for more information. If you require this as
656 /// a bot, re-think what you are doing and if it _really_ needs to be doing this.
657 ///
658 /// # Examples
659 ///
660 /// Create a guild called `"test"` in the [US West region] with no icon:
661 ///
662 /// ```rust,ignore
663 /// use serenity::model::Guild;
664 ///
665 /// let _guild = Guild::create_guild(&http, "test", None).await;
666 /// ```
667 ///
668 /// # Errors
669 ///
670 /// Returns [`Error::Http`] if the current user cannot create a Guild.
671 ///
672 /// [`Shard`]: crate::gateway::Shard
673 /// [whitelist]: https://discord.com/developers/docs/resources/guild#create-guild
674 #[deprecated = "This endpoint has been deprecated by Discord and will stop functioning after July 15, 2025. For more information, see: https://discord.com/developers/docs/change-log#deprecating-guild-creation-by-apps"]
675 pub async fn create(
676 http: impl AsRef<Http>,
677 name: &str,
678 icon: Option<ImageHash>,
679 ) -> Result<PartialGuild> {
680 let map = json!({
681 "icon": icon,
682 "name": name,
683 });
684
685 #[allow(deprecated)]
686 http.as_ref().create_guild(&map).await
687 }
688
689 /// Creates a new [`Channel`] in the guild.
690 ///
691 /// **Note**: Requires the [Manage Channels] permission.
692 ///
693 /// # Examples
694 ///
695 /// ```rust,no_run
696 /// # use serenity::http::Http;
697 /// # use serenity::model::guild::Guild;
698 /// # use serenity::model::id::GuildId;
699 /// use serenity::builder::CreateChannel;
700 /// use serenity::model::channel::ChannelType;
701 ///
702 /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
703 /// # let http: Http = unimplemented!();
704 /// # let guild = Guild::get(&http, GuildId::new(7)).await?;
705 /// let builder = CreateChannel::new("my-test-channel").kind(ChannelType::Text);
706 ///
707 /// // assuming a `guild` has already been bound
708 /// let _channel = guild.create_channel(&http, builder).await?;
709 /// # Ok(())
710 /// # }
711 /// ```
712 ///
713 /// # Errors
714 ///
715 /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`] if the current user
716 /// lacks permission. Otherwise returns [`Error::Http`], as well as if invalid data is given.
717 ///
718 /// [Manage Channels]: Permissions::MANAGE_CHANNELS
719 pub async fn create_channel(
720 &self,
721 cache_http: impl CacheHttp,
722 builder: CreateChannel<'_>,
723 ) -> Result<GuildChannel> {
724 self.id.create_channel(cache_http, builder).await
725 }
726
727 /// Creates an emoji in the guild with a name and base64-encoded image. The
728 /// [`CreateAttachment`] builder is provided for you as a simple method to read an image and
729 /// encode it into base64, if you are reading from the filesystem.
730 ///
731 /// The name of the emoji must be at least 2 characters long and can only contain alphanumeric
732 /// characters and underscores.
733 ///
734 /// Requires the [Create Guild Expressions] permission.
735 ///
736 /// # Examples
737 ///
738 /// See the [`EditProfile::avatar`] example for an in-depth example as to how to read an image
739 /// from the filesystem and encode it as base64. Most of the example can be applied similarly
740 /// for this method.
741 ///
742 /// # Errors
743 ///
744 /// Returns [`Error::Http`] if the current user lacks permission.
745 ///
746 /// [`EditProfile::avatar`]: crate::builder::EditProfile::avatar
747 /// [`CreateAttachment`]: crate::builder::CreateAttachment
748 /// [Create Guild Expressions]: Permissions::CREATE_GUILD_EXPRESSIONS
749 #[inline]
750 pub async fn create_emoji(
751 &self,
752 http: impl AsRef<Http>,
753 name: &str,
754 image: &str,
755 ) -> Result<Emoji> {
756 self.id.create_emoji(http, name, image).await
757 }
758
759 /// Creates an integration for the guild.
760 ///
761 /// Requires the [Manage Guild] permission.
762 ///
763 /// # Errors
764 ///
765 /// Returns [`Error::Http`] if the current user lacks permission.
766 ///
767 /// [Manage Guild]: Permissions::MANAGE_GUILD
768 #[inline]
769 pub async fn create_integration(
770 &self,
771 http: impl AsRef<Http>,
772 integration_id: impl Into<IntegrationId>,
773 kind: &str,
774 ) -> Result<()> {
775 self.id.create_integration(http, integration_id, kind).await
776 }
777
778 /// Create a guild specific application [`Command`].
779 ///
780 /// **Note**: Unlike global commands, guild commands will update instantly.
781 ///
782 /// # Errors
783 ///
784 /// See [`CreateCommand::execute`] for a list of possible errors.
785 ///
786 /// [`CreateCommand::execute`]: ../../builder/struct.CreateCommand.html#method.execute
787 #[inline]
788 pub async fn create_command(
789 &self,
790 cache_http: impl CacheHttp,
791 builder: CreateCommand,
792 ) -> Result<Command> {
793 self.id.create_command(cache_http, builder).await
794 }
795
796 /// Override all guild application commands.
797 ///
798 /// # Errors
799 ///
800 /// Returns the same errors as [`Self::create_command`].
801 pub async fn set_commands(
802 &self,
803 http: impl AsRef<Http>,
804 commands: Vec<CreateCommand>,
805 ) -> Result<Vec<Command>> {
806 self.id.set_commands(http, commands).await
807 }
808
809 /// Overwrites permissions for a specific command.
810 ///
811 /// **Note**: It will update instantly.
812 ///
813 /// # Errors
814 ///
815 /// See [`CreateCommandPermissionsData::execute`] for a list of possible errors.
816 ///
817 /// [`CreateCommandPermissionsData::execute`]: ../../builder/struct.CreateCommandPermissionsData.html#method.execute
818 pub async fn edit_command_permissions(
819 &self,
820 cache_http: impl CacheHttp,
821 command_id: CommandId,
822 builder: EditCommandPermissions,
823 ) -> Result<CommandPermissions> {
824 self.id.edit_command_permissions(cache_http, command_id, builder).await
825 }
826
827 /// Get all guild application commands.
828 ///
829 /// # Errors
830 ///
831 /// If there is an error, it will be either [`Error::Http`] or [`Error::Json`].
832 pub async fn get_commands(&self, http: impl AsRef<Http>) -> Result<Vec<Command>> {
833 self.id.get_commands(http).await
834 }
835
836 /// Get all guild application commands with localizations.
837 ///
838 /// # Errors
839 ///
840 /// If there is an error, it will be either [`Error::Http`] or [`Error::Json`].
841 pub async fn get_commands_with_localizations(
842 &self,
843 http: impl AsRef<Http>,
844 ) -> Result<Vec<Command>> {
845 self.id.get_commands_with_localizations(http).await
846 }
847
848 /// Get a specific guild application command by its Id.
849 ///
850 /// # Errors
851 ///
852 /// If there is an error, it will be either [`Error::Http`] or [`Error::Json`].
853 pub async fn get_command(
854 &self,
855 http: impl AsRef<Http>,
856 command_id: CommandId,
857 ) -> Result<Command> {
858 self.id.get_command(http, command_id).await
859 }
860
861 /// Edit a guild application command, given its Id.
862 ///
863 /// # Errors
864 ///
865 /// See [`CreateCommand::execute`] for a list of possible errors.
866 ///
867 /// [`CreateCommand::execute`]: ../../builder/struct.CreateCommand.html#method.execute
868 pub async fn edit_command(
869 &self,
870 cache_http: impl CacheHttp,
871 command_id: CommandId,
872 builder: CreateCommand,
873 ) -> Result<Command> {
874 self.id.edit_command(cache_http, command_id, builder).await
875 }
876
877 /// Delete guild application command by its Id.
878 ///
879 /// # Errors
880 ///
881 /// If there is an error, it will be either [`Error::Http`] or [`Error::Json`].
882 pub async fn delete_command(
883 &self,
884 http: impl AsRef<Http>,
885 command_id: CommandId,
886 ) -> Result<()> {
887 self.id.delete_command(http, command_id).await
888 }
889
890 /// Get all guild application commands permissions only.
891 ///
892 /// # Errors
893 ///
894 /// If there is an error, it will be either [`Error::Http`] or [`Error::Json`].
895 pub async fn get_commands_permissions(
896 &self,
897 http: impl AsRef<Http>,
898 ) -> Result<Vec<CommandPermissions>> {
899 self.id.get_commands_permissions(http).await
900 }
901
902 /// Get permissions for specific guild application command by its Id.
903 ///
904 /// # Errors
905 ///
906 /// If there is an error, it will be either [`Error::Http`] or [`Error::Json`].
907 pub async fn get_command_permissions(
908 &self,
909 http: impl AsRef<Http>,
910 command_id: CommandId,
911 ) -> Result<CommandPermissions> {
912 self.id.get_command_permissions(http, command_id).await
913 }
914
915 /// Creates a new role in the guild with the data set, if any.
916 ///
917 /// **Note**: Requires the [Manage Roles] permission.
918 ///
919 /// # Examples
920 ///
921 /// See the documentation for [`EditRole`] for details.
922 ///
923 /// # Errors
924 ///
925 /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`] if the current user
926 /// lacks permission. Otherwise returns [`Error::Http`], as well as if invalid data is given.
927 ///
928 /// [Manage Roles]: Permissions::MANAGE_ROLES
929 pub async fn create_role(
930 &self,
931 cache_http: impl CacheHttp,
932 builder: EditRole<'_>,
933 ) -> Result<Role> {
934 self.id.create_role(cache_http, builder).await
935 }
936
937 /// Creates a new scheduled event in the guild with the data set, if any.
938 ///
939 /// **Note**: Requires the [Create Events] permission.
940 ///
941 /// # Errors
942 ///
943 /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`] if the current user
944 /// lacks permission. Otherwise returns [`Error::Http`], as well as if invalid data is given.
945 ///
946 /// [Create Events]: Permissions::CREATE_EVENTS
947 pub async fn create_scheduled_event(
948 &self,
949 cache_http: impl CacheHttp,
950 builder: CreateScheduledEvent<'_>,
951 ) -> Result<ScheduledEvent> {
952 self.id.create_scheduled_event(cache_http, builder).await
953 }
954
955 /// Creates a new sticker in the guild with the data set, if any.
956 ///
957 /// **Note**: Requires the [Create Guild Expressions] permission.
958 ///
959 /// # Errors
960 ///
961 /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`] if the current user
962 /// lacks permission. Otherwise returns [`Error::Http`], as well as if invalid data is given.
963 ///
964 /// [Create Guild Expressions]: Permissions::CREATE_GUILD_EXPRESSIONS
965 pub async fn create_sticker(
966 &self,
967 cache_http: impl CacheHttp,
968 builder: CreateSticker<'_>,
969 ) -> Result<Sticker> {
970 self.id.create_sticker(cache_http.http(), builder).await
971 }
972
973 /// Deletes the current guild if the current user is the owner of the
974 /// guild.
975 ///
976 /// **Note**: Requires the current user to be the owner of the guild.
977 ///
978 /// # Errors
979 ///
980 /// If the `cache` is enabled, then returns a [`ModelError::InvalidUser`] if the current user
981 /// is not the guild owner.
982 ///
983 /// Otherwise returns [`Error::Http`] if the current user is not the owner of the guild.
984 pub async fn delete(&self, cache_http: impl CacheHttp) -> Result<()> {
985 #[cfg(feature = "cache")]
986 {
987 if let Some(cache) = cache_http.cache() {
988 if self.owner_id != cache.current_user().id {
989 return Err(Error::Model(ModelError::InvalidUser));
990 }
991 }
992 }
993
994 self.id.delete(cache_http.http()).await
995 }
996
997 /// Deletes an [`Emoji`] from the guild.
998 ///
999 /// **Note**: If the emoji was created by the current user, requires either the [Create Guild
1000 /// Expressions] or the [Manage Guild Expressions] permission. Otherwise, the [Manage Guild
1001 /// Expressions] permission is required.
1002 ///
1003 /// # Errors
1004 ///
1005 /// Returns [`Error::Http`] if the current user lacks permission, or if an emoji with the given
1006 /// id does not exist in the guild.
1007 ///
1008 /// [Create Guild Expressions]: Permissions::CREATE_GUILD_EXPRESSIONS
1009 /// [Manage Guild Expressions]: Permissions::MANAGE_GUILD_EXPRESSIONS
1010 #[inline]
1011 pub async fn delete_emoji(
1012 &self,
1013 http: impl AsRef<Http>,
1014 emoji_id: impl Into<EmojiId>,
1015 ) -> Result<()> {
1016 self.id.delete_emoji(http, emoji_id).await
1017 }
1018
1019 /// Deletes an integration by Id from the guild.
1020 ///
1021 /// Requires the [Manage Guild] permission.
1022 ///
1023 /// # Errors
1024 ///
1025 /// Returns an [`Error::Http`] if the current user lacks permission, or if an Integration with
1026 /// that Id does not exist.
1027 ///
1028 /// [Manage Guild]: Permissions::MANAGE_GUILD
1029 #[inline]
1030 pub async fn delete_integration(
1031 &self,
1032 http: impl AsRef<Http>,
1033 integration_id: impl Into<IntegrationId>,
1034 ) -> Result<()> {
1035 self.id.delete_integration(http, integration_id).await
1036 }
1037
1038 /// Deletes a [`Role`] by Id from the guild.
1039 ///
1040 /// Also see [`Role::delete`] if you have the `cache` and `model` features enabled.
1041 ///
1042 /// Requires the [Manage Roles] permission.
1043 ///
1044 /// # Errors
1045 ///
1046 /// Returns [`Error::Http`] if the current user lacks permission to delete the role.
1047 ///
1048 /// [Manage Roles]: Permissions::MANAGE_ROLES
1049 #[inline]
1050 pub async fn delete_role(
1051 &self,
1052 http: impl AsRef<Http>,
1053 role_id: impl Into<RoleId>,
1054 ) -> Result<()> {
1055 self.id.delete_role(http, role_id).await
1056 }
1057
1058 /// Deletes a [`ScheduledEvent`] by id from the guild.
1059 ///
1060 /// **Note**: If the event was created by the current user, requires either [Create Events] or
1061 /// the [Manage Events] permission. Otherwise, the [Manage Events] permission is required.
1062 ///
1063 /// # Errors
1064 ///
1065 /// Returns [`Error::Http`] if the current user lacks permission to delete the scheduled event.
1066 ///
1067 /// [Create Events]: Permissions::CREATE_EVENTS
1068 /// [Manage Events]: Permissions::MANAGE_EVENTS
1069 #[inline]
1070 pub async fn delete_scheduled_event(
1071 &self,
1072 http: impl AsRef<Http>,
1073 event_id: impl Into<ScheduledEventId>,
1074 ) -> Result<()> {
1075 self.id.delete_scheduled_event(http, event_id).await
1076 }
1077
1078 /// Deletes a [`Sticker`] by Id from the guild.
1079 ///
1080 /// **Note**: If the sticker was created by the current user, requires either the [Create Guild
1081 /// Expressions] or the [Manage Guild Expressions] permission. Otherwise, the [Manage Guild
1082 /// Expressions] permission is required.
1083 ///
1084 /// # Errors
1085 ///
1086 /// Returns [`Error::Http`] if the current user lacks permission, or if a sticker with that id
1087 /// does not exist.
1088 ///
1089 /// [Create Guild Expressions]: Permissions::CREATE_GUILD_EXPRESSIONS
1090 /// [Manage Guild Expressions]: Permissions::MANAGE_GUILD_EXPRESSIONS
1091 #[inline]
1092 pub async fn delete_sticker(
1093 &self,
1094 http: impl AsRef<Http>,
1095 sticker_id: impl Into<StickerId>,
1096 ) -> Result<()> {
1097 self.id.delete_sticker(http, sticker_id).await
1098 }
1099
1100 /// Edits the current guild with new data where specified.
1101 ///
1102 /// **Note**: Requires the [Manage Guild] permission.
1103 ///
1104 /// # Examples
1105 ///
1106 /// Change a guild's icon using a file named "icon.png":
1107 ///
1108 /// ```rust,no_run
1109 /// # use serenity::builder::{EditGuild, CreateAttachment};
1110 /// # use serenity::{http::Http, model::guild::Guild};
1111 /// #
1112 /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
1113 /// # let http: Http = unimplemented!();
1114 /// # let mut guild: Guild = unimplemented!();
1115 /// let icon = CreateAttachment::path("./icon.png").await?;
1116 ///
1117 /// // assuming a `guild` has already been bound
1118 /// let builder = EditGuild::new().icon(Some(&icon));
1119 /// guild.edit(&http, builder).await?;
1120 /// # Ok(())
1121 /// # }
1122 /// ```
1123 ///
1124 /// # Errors
1125 ///
1126 /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`] if the current user
1127 /// lacks permission. Otherwise returns [`Error::Http`], as well as if invalid data is given.
1128 ///
1129 /// [Manage Guild]: Permissions::MANAGE_GUILD
1130 pub async fn edit(&mut self, cache_http: impl CacheHttp, builder: EditGuild<'_>) -> Result<()> {
1131 let guild = self.id.edit(cache_http, builder).await?;
1132
1133 self.afk_metadata = guild.afk_metadata;
1134 self.default_message_notifications = guild.default_message_notifications;
1135 self.emojis = guild.emojis;
1136 self.features = guild.features;
1137 self.icon = guild.icon;
1138 self.mfa_level = guild.mfa_level;
1139 self.name = guild.name;
1140 self.owner_id = guild.owner_id;
1141 self.roles = guild.roles;
1142 self.splash = guild.splash;
1143 self.verification_level = guild.verification_level;
1144
1145 Ok(())
1146 }
1147
1148 /// Edits an [`Emoji`]'s name in the guild.
1149 ///
1150 /// Also see [`Emoji::edit`] if you have the `cache` and `model` features enabled.
1151 ///
1152 /// **Note**: If the emoji was created by the current user, requires either the [Create Guild
1153 /// Expressions] or the [Manage Guild Expressions] permission. Otherwise, the [Manage Guild
1154 /// Expressions] permission is required.
1155 ///
1156 /// # Errors
1157 ///
1158 /// Returns [`Error::Http`] if the current user lacks permission, or if an emoji with the given
1159 /// id does not exist.
1160 ///
1161 /// [Create Guild Expressions]: Permissions::CREATE_GUILD_EXPRESSIONS
1162 /// [Manage Guild Expressions]: Permissions::MANAGE_GUILD_EXPRESSIONS
1163 #[inline]
1164 pub async fn edit_emoji(
1165 &self,
1166 http: impl AsRef<Http>,
1167 emoji_id: impl Into<EmojiId>,
1168 name: &str,
1169 ) -> Result<Emoji> {
1170 self.id.edit_emoji(http, emoji_id, name).await
1171 }
1172
1173 /// Edits the properties a guild member, such as muting or nicknaming them. Returns the new
1174 /// member.
1175 ///
1176 /// Refer to the documentation of [`EditMember`] for a full list of methods and permission
1177 /// restrictions.
1178 ///
1179 /// # Examples
1180 ///
1181 /// See [`GuildId::edit_member`] for details.
1182 ///
1183 /// # Errors
1184 ///
1185 /// Returns [`Error::Http`] if the current user lacks permission, or if invalid data is given.
1186 #[inline]
1187 pub async fn edit_member(
1188 &self,
1189 cache_http: impl CacheHttp,
1190 user_id: impl Into<UserId>,
1191 builder: EditMember<'_>,
1192 ) -> Result<Member> {
1193 self.id.edit_member(cache_http, user_id, builder).await
1194 }
1195
1196 /// Edits the guild's MFA level. Returns the new level on success.
1197 ///
1198 /// Requires guild ownership.
1199 ///
1200 /// # Errors
1201 ///
1202 /// Returns [`Error::Http`] if the current user lacks permission.
1203 pub async fn edit_mfa_level(
1204 &self,
1205 http: impl AsRef<Http>,
1206 mfa_level: MfaLevel,
1207 audit_log_reason: Option<&str>,
1208 ) -> Result<MfaLevel> {
1209 self.id.edit_mfa_level(http, mfa_level, audit_log_reason).await
1210 }
1211
1212 /// Edits the current user's nickname for the guild.
1213 ///
1214 /// Pass [`None`] to reset the nickname.
1215 ///
1216 /// **Note**: Requires the [Change Nickname] permission.
1217 ///
1218 /// # Errors
1219 ///
1220 /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`] if the current user
1221 /// does not have permission to change their own nickname.
1222 ///
1223 /// Otherwise will return [`Error::Http`] if the current user lacks permission.
1224 ///
1225 /// [Change Nickname]: Permissions::CHANGE_NICKNAME
1226 pub async fn edit_nickname(
1227 &self,
1228 cache_http: impl CacheHttp,
1229 new_nickname: Option<&str>,
1230 ) -> Result<()> {
1231 #[cfg(feature = "cache")]
1232 {
1233 if let Some(cache) = cache_http.cache() {
1234 self.require_perms(cache, Permissions::CHANGE_NICKNAME)?;
1235 }
1236 }
1237
1238 self.id.edit_nickname(cache_http.http(), new_nickname).await
1239 }
1240
1241 /// Edits a role, optionally setting its fields.
1242 ///
1243 /// **Note**: Requires the [Manage Roles] permission.
1244 ///
1245 /// # Examples
1246 ///
1247 /// See the documentation of [`GuildId::edit_role`] for details.
1248 ///
1249 /// # Errors
1250 ///
1251 /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`] if the current user
1252 /// lacks permission. Otherwise returns [`Error::Http`], as well as if invalid data is given.
1253 ///
1254 /// [Manage Roles]: Permissions::MANAGE_ROLES
1255 #[inline]
1256 pub async fn edit_role(
1257 &self,
1258 cache_http: impl CacheHttp,
1259 role_id: impl Into<RoleId>,
1260 builder: EditRole<'_>,
1261 ) -> Result<Role> {
1262 self.id.edit_role(cache_http, role_id, builder).await
1263 }
1264
1265 /// Edits the order of [`Role`]s. Requires the [Manage Roles] permission.
1266 ///
1267 /// # Examples
1268 ///
1269 /// Change the order of a role:
1270 ///
1271 /// ```rust,ignore
1272 /// use serenity::model::id::RoleId;
1273 /// guild.edit_role_position(&context, RoleId::new(8), 2);
1274 /// ```
1275 ///
1276 /// # Errors
1277 ///
1278 /// Returns [`Error::Http`] if the current user lacks permission.
1279 ///
1280 /// [Manage Roles]: Permissions::MANAGE_ROLES
1281 #[inline]
1282 pub async fn edit_role_position(
1283 &self,
1284 http: impl AsRef<Http>,
1285 role_id: impl Into<RoleId>,
1286 position: u16,
1287 ) -> Result<Vec<Role>> {
1288 self.id.edit_role_position(http, role_id, position).await
1289 }
1290
1291 /// Modifies a scheduled event in the guild with the data set, if any.
1292 ///
1293 /// **Note**: If the event was created by the current user, requires either [Create Events] or
1294 /// the [Manage Events] permission. Otherwise, the [Manage Events] permission is required.
1295 ///
1296 /// # Errors
1297 ///
1298 /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`] if the current user
1299 /// lacks permission. Otherwise returns [`Error::Http`], as well as if invalid data is given.
1300 ///
1301 /// [Create Events]: Permissions::CREATE_EVENTS
1302 /// [Manage Events]: Permissions::MANAGE_EVENTS
1303 pub async fn edit_scheduled_event(
1304 &self,
1305 cache_http: impl CacheHttp,
1306 event_id: impl Into<ScheduledEventId>,
1307 builder: EditScheduledEvent<'_>,
1308 ) -> Result<ScheduledEvent> {
1309 self.id.edit_scheduled_event(cache_http, event_id, builder).await
1310 }
1311
1312 /// Edits a sticker.
1313 ///
1314 /// **Note**: If the sticker was created by the current user, requires either the [Create Guild
1315 /// Expressions] or the [Manage Guild Expressions] permission. Otherwise, the [Manage Guild
1316 /// Expressions] permission is required.
1317 ///
1318 /// # Examples
1319 ///
1320 /// Rename a sticker:
1321 ///
1322 /// ```rust,no_run
1323 /// # use serenity::http::Http;
1324 /// # use serenity::model::guild::Guild;
1325 /// # use serenity::model::id::GuildId;
1326 /// use serenity::builder::EditSticker;
1327 /// use serenity::model::id::StickerId;
1328 ///
1329 /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
1330 /// # let http: Http = unimplemented!();
1331 /// # let guild: Guild = unimplemented!();
1332 /// let builder = EditSticker::new().name("Bun bun meow");
1333 /// guild.edit_sticker(&http, StickerId::new(7), builder).await?;
1334 /// # Ok(())
1335 /// # }
1336 /// ```
1337 ///
1338 /// # Errors
1339 ///
1340 /// Returns [`Error::Http`] if the current user lacks permission, or if invalid data is given.
1341 ///
1342 /// [Create Guild Expressions]: Permissions::CREATE_GUILD_EXPRESSIONS
1343 /// [Manage Guild Expressions]: Permissions::MANAGE_GUILD_EXPRESSIONS
1344 #[inline]
1345 pub async fn edit_sticker(
1346 &self,
1347 cache_http: impl CacheHttp,
1348 sticker_id: impl Into<StickerId>,
1349 builder: EditSticker<'_>,
1350 ) -> Result<Sticker> {
1351 self.id.edit_sticker(cache_http, sticker_id, builder).await
1352 }
1353
1354 /// Edits the guild's welcome screen.
1355 ///
1356 /// **Note**: Requires the [Manage Guild] permission.
1357 ///
1358 /// # Errors
1359 ///
1360 /// Returns [`Error::Http`] if the current user lacks permission.
1361 ///
1362 /// [Manage Guild]: Permissions::MANAGE_GUILD
1363 pub async fn edit_welcome_screen(
1364 &self,
1365 cache_http: impl CacheHttp,
1366 builder: EditGuildWelcomeScreen<'_>,
1367 ) -> Result<GuildWelcomeScreen> {
1368 self.id.edit_welcome_screen(cache_http, builder).await
1369 }
1370
1371 /// Edits the guild's widget.
1372 ///
1373 /// **Note**: Requires the [Manage Guild] permission.
1374 ///
1375 /// # Errors
1376 ///
1377 /// Returns [`Error::Http`] if the current user lacks permission.
1378 ///
1379 /// [Manage Guild]: Permissions::MANAGE_GUILD
1380 pub async fn edit_widget(
1381 &self,
1382 cache_http: impl CacheHttp,
1383 builder: EditGuildWidget<'_>,
1384 ) -> Result<GuildWidget> {
1385 self.id.edit_widget(cache_http, builder).await
1386 }
1387
1388 /// Gets a partial amount of guild data by its Id.
1389 ///
1390 /// **Note**: This will not be a [`Guild`], as the REST API does not send all data with a guild
1391 /// retrieval.
1392 ///
1393 /// # Errors
1394 ///
1395 /// Returns an [`Error::Http`] if the current user is not in the guild.
1396 #[inline]
1397 pub async fn get(
1398 cache_http: impl CacheHttp,
1399 guild_id: impl Into<GuildId>,
1400 ) -> Result<PartialGuild> {
1401 guild_id.into().to_partial_guild(cache_http).await
1402 }
1403
1404 /// Gets the highest role a [`Member`] of this Guild has.
1405 ///
1406 /// Returns None if the member has no roles or the member from this guild.
1407 #[must_use]
1408 pub fn member_highest_role(&self, member: &Member) -> Option<&Role> {
1409 let mut highest: Option<&Role> = None;
1410
1411 for role_id in &member.roles {
1412 if let Some(role) = self.roles.get(role_id) {
1413 // Skip this role if this role in iteration has:
1414 // - a position less than the recorded highest
1415 // - a position equal to the recorded, but a higher ID
1416 if let Some(highest) = highest {
1417 if role.position < highest.position
1418 || (role.position == highest.position && role.id > highest.id)
1419 {
1420 continue;
1421 }
1422 }
1423
1424 highest = Some(role);
1425 }
1426 }
1427
1428 highest
1429 }
1430
1431 /// Returns which of two [`User`]s has a higher [`Member`] hierarchy.
1432 ///
1433 /// Hierarchy is essentially who has the [`Role`] with the highest [`position`].
1434 ///
1435 /// Returns [`None`] if at least one of the given users' member instances is not present.
1436 /// Returns [`None`] if the users have the same hierarchy, as neither are greater than the
1437 /// other.
1438 ///
1439 /// If both user IDs are the same, [`None`] is returned. If one of the users is the guild
1440 /// owner, their ID is returned.
1441 ///
1442 /// [`position`]: Role::position
1443 #[cfg(feature = "cache")]
1444 #[inline]
1445 pub fn greater_member_hierarchy(
1446 &self,
1447 #[allow(unused_variables)] _cache: impl AsRef<Cache>,
1448 lhs_id: impl Into<UserId>,
1449 rhs_id: impl Into<UserId>,
1450 ) -> Option<UserId> {
1451 self.greater_member_hierarchy_(lhs_id.into(), rhs_id.into())
1452 }
1453
1454 #[cfg(feature = "cache")]
1455 fn greater_member_hierarchy_(&self, lhs_id: UserId, rhs_id: UserId) -> Option<UserId> {
1456 // Check that the IDs are the same. If they are, neither is greater.
1457 if lhs_id == rhs_id {
1458 return None;
1459 }
1460
1461 // Check if either user is the guild owner.
1462 if lhs_id == self.owner_id {
1463 return Some(lhs_id);
1464 } else if rhs_id == self.owner_id {
1465 return Some(rhs_id);
1466 }
1467
1468 let lhs = self
1469 .member_highest_role(self.members.get(&lhs_id)?)
1470 .map_or((RoleId::new(1), 0), |r| (r.id, r.position));
1471
1472 let rhs = self
1473 .member_highest_role(self.members.get(&rhs_id)?)
1474 .map_or((RoleId::new(1), 0), |r| (r.id, r.position));
1475
1476 // If LHS and RHS both have no top position or have the same role ID, then no one wins.
1477 if (lhs.1 == 0 && rhs.1 == 0) || (lhs.0 == rhs.0) {
1478 return None;
1479 }
1480
1481 // If LHS's top position is higher than RHS, then LHS wins.
1482 if lhs.1 > rhs.1 {
1483 return Some(lhs_id);
1484 }
1485
1486 // If RHS's top position is higher than LHS, then RHS wins.
1487 if rhs.1 > lhs.1 {
1488 return Some(rhs_id);
1489 }
1490
1491 // If LHS and RHS both have the same position, but LHS has the lower role ID, then LHS
1492 // wins.
1493 //
1494 // If RHS has the higher role ID, then RHS wins.
1495 if lhs.1 == rhs.1 && lhs.0 < rhs.0 {
1496 Some(lhs_id)
1497 } else {
1498 Some(rhs_id)
1499 }
1500 }
1501
1502 /// Returns the formatted URL of the guild's icon, if one exists.
1503 ///
1504 /// This will produce a WEBP image URL, or GIF if the guild has a GIF icon.
1505 #[must_use]
1506 pub fn icon_url(&self) -> Option<String> {
1507 icon_url(self.id, self.icon.as_ref())
1508 }
1509
1510 /// Gets all [`Emoji`]s of this guild via HTTP.
1511 ///
1512 /// # Errors
1513 ///
1514 /// Returns [`Error::Http`] if the guild is unavailable
1515 #[inline]
1516 pub async fn emojis(&self, http: impl AsRef<Http>) -> Result<Vec<Emoji>> {
1517 self.id.emojis(http).await
1518 }
1519
1520 /// Gets an [`Emoji`] of this guild by its ID via HTTP.
1521 ///
1522 /// # Errors
1523 ///
1524 /// Returns an [`Error::Http`] if an emoji with that id does not exist in the guild, or if the
1525 /// guild is unavailable.
1526 ///
1527 /// May also return [`Error::Json`] if there is an error in deserializing the API response.
1528 #[inline]
1529 pub async fn emoji(&self, http: impl AsRef<Http>, emoji_id: EmojiId) -> Result<Emoji> {
1530 self.id.emoji(http, emoji_id).await
1531 }
1532
1533 /// Gets all integration of the guild.
1534 ///
1535 /// **Note**: Requires the [Manage Guild] permission.
1536 ///
1537 /// # Errors
1538 ///
1539 /// Returns [`Error::Http`] if the current user does not have permission to see integrations.
1540 ///
1541 /// May also return [`Error::Json`] if there is an error in deserializing the API response.
1542 ///
1543 /// [Manage Guild]: Permissions::MANAGE_GUILD
1544 #[inline]
1545 pub async fn integrations(&self, http: impl AsRef<Http>) -> Result<Vec<Integration>> {
1546 self.id.integrations(http).await
1547 }
1548
1549 /// Retrieves the active invites for the guild.
1550 ///
1551 /// **Note**: Requires the [Manage Guild] permission.
1552 ///
1553 /// # Errors
1554 ///
1555 /// If the `cache` is enabled, returns [`ModelError::InvalidPermissions`] if the current user
1556 /// does not have permission to see invites.
1557 ///
1558 /// Otherwise will return [`Error::Http`] if the current user does not have permission.
1559 ///
1560 /// [Manage Guild]: Permissions::MANAGE_GUILD
1561 pub async fn invites(&self, cache_http: impl CacheHttp) -> Result<Vec<RichInvite>> {
1562 #[cfg(feature = "cache")]
1563 {
1564 if let Some(cache) = cache_http.cache() {
1565 self.require_perms(cache, Permissions::MANAGE_GUILD)?;
1566 }
1567 }
1568
1569 self.id.invites(cache_http.http()).await
1570 }
1571
1572 /// Checks if the guild is 'large'.
1573 ///
1574 /// A guild is considered large if it has more than 250 members.
1575 #[inline]
1576 #[must_use]
1577 #[deprecated = "Use Guild::large"]
1578 pub fn is_large(&self) -> bool {
1579 self.member_count > u64::from(LARGE_THRESHOLD)
1580 }
1581
1582 /// Kicks a [`Member`] from the guild.
1583 ///
1584 /// Requires the [Kick Members] permission.
1585 ///
1586 /// # Errors
1587 ///
1588 /// Returns [`Error::Http`] if the member cannot be kicked by the current user.
1589 ///
1590 /// [Kick Members]: Permissions::KICK_MEMBERS
1591 #[inline]
1592 pub async fn kick(&self, http: impl AsRef<Http>, user_id: impl Into<UserId>) -> Result<()> {
1593 self.id.kick(http, user_id).await
1594 }
1595
1596 /// # Errors
1597 ///
1598 /// In addition to the reasons [`Self::kick`] may return an error, may also return an error if
1599 /// the reason is too long.
1600 #[inline]
1601 pub async fn kick_with_reason(
1602 &self,
1603 http: impl AsRef<Http>,
1604 user_id: impl Into<UserId>,
1605 reason: &str,
1606 ) -> Result<()> {
1607 self.id.kick_with_reason(http, user_id, reason).await
1608 }
1609
1610 /// Returns a guild [`Member`] object for the current user.
1611 ///
1612 /// See [`Http::get_current_user_guild_member`] for more.
1613 ///
1614 /// # Errors
1615 ///
1616 /// Returns an [`Error::Http`] if the current user is not in the guild or the access token
1617 /// lacks the necessary scope.
1618 #[inline]
1619 pub async fn current_user_member(&self, http: impl AsRef<Http>) -> Result<Member> {
1620 self.id.current_user_member(http).await
1621 }
1622
1623 /// Leaves the guild.
1624 ///
1625 /// # Errors
1626 ///
1627 /// May return an [`Error::Http`] if the current user cannot leave the guild, or currently is
1628 /// not in the guild.
1629 #[inline]
1630 pub async fn leave(&self, http: impl AsRef<Http>) -> Result<()> {
1631 self.id.leave(http).await
1632 }
1633
1634 /// Gets a user's [`Member`] for the guild by Id.
1635 ///
1636 /// If the cache feature is enabled [`Self::members`] will be checked first, if so, a reference
1637 /// to the member will be returned.
1638 ///
1639 /// # Errors
1640 ///
1641 /// Returns an [`Error::Http`] if the user is not in the guild or if the guild is otherwise
1642 /// unavailable.
1643 #[inline]
1644 pub async fn member(
1645 &self,
1646 cache_http: impl CacheHttp,
1647 user_id: impl Into<UserId>,
1648 ) -> Result<Cow<'_, Member>> {
1649 let user_id = user_id.into();
1650
1651 if let Some(member) = self.members.get(&user_id) {
1652 Ok(Cow::Borrowed(member))
1653 } else {
1654 cache_http.http().get_member(self.id, user_id).await.map(Cow::Owned)
1655 }
1656 }
1657
1658 /// Gets a list of the guild's members.
1659 ///
1660 /// Optionally pass in the `limit` to limit the number of results. Minimum value is 1, maximum
1661 /// and default value is 1000.
1662 ///
1663 /// Optionally pass in `after` to offset the results by a [`User`]'s Id.
1664 ///
1665 /// # Errors
1666 ///
1667 /// Returns an [`Error::Http`] if the API returns an error, may also return
1668 /// [`Error::NotInRange`] if the input is not within range.
1669 ///
1670 /// [`User`]: crate::model::user::User
1671 #[inline]
1672 pub async fn members(
1673 &self,
1674 http: impl AsRef<Http>,
1675 limit: Option<u64>,
1676 after: impl Into<Option<UserId>>,
1677 ) -> Result<Vec<Member>> {
1678 self.id.members(http, limit, after).await
1679 }
1680
1681 /// Gets a list of all the members (satisfying the status provided to the function) in this
1682 /// guild.
1683 pub fn members_with_status(&self, status: OnlineStatus) -> impl Iterator<Item = &Member> {
1684 self.members.iter().filter_map(move |(id, member)| match self.presences.get(id) {
1685 Some(presence) if presence.status == status => Some(member),
1686 _ => None,
1687 })
1688 }
1689
1690 /// Retrieves the first [`Member`] found that matches the name - with an optional discriminator
1691 /// - provided.
1692 ///
1693 /// Searching with a discriminator given is the most precise form of lookup, as no two people
1694 /// can share the same username *and* discriminator.
1695 ///
1696 /// If a member can not be found by username or username#discriminator, then a search will be
1697 /// done for the nickname. When searching by nickname, the hash (`#`) and everything after it
1698 /// is included in the search.
1699 ///
1700 /// The following are valid types of searches:
1701 /// - **username**: "zey"
1702 /// - **username and discriminator**: "zey#5479"
1703 ///
1704 /// **Note**: This will only search members that are cached. If you want to search all members
1705 /// in the guild via the Http API, use [`Self::search_members`].
1706 #[must_use]
1707 pub fn member_named(&self, name: &str) -> Option<&Member> {
1708 let (username, discrim) = match crate::utils::parse_user_tag(name) {
1709 Some((username, discrim)) => (username, Some(discrim)),
1710 None => (name, None),
1711 };
1712
1713 for member in self.members.values() {
1714 if member.user.name == username
1715 && discrim.map_or(true, |d| member.user.discriminator == d)
1716 {
1717 return Some(member);
1718 }
1719 }
1720
1721 self.members.values().find(|member| member.nick.as_ref().is_some_and(|nick| nick == name))
1722 }
1723
1724 /// Retrieves all [`Member`] that start with a given [`String`].
1725 ///
1726 /// `sorted` decides whether the best early match of the `prefix` should be the criteria to
1727 /// sort the result.
1728 ///
1729 /// For the `prefix` "zey" and the unsorted result:
1730 /// - "zeya", "zeyaa", "zeyla", "zeyzey", "zeyzeyzey"
1731 ///
1732 /// It would be sorted:
1733 /// - "zeya", "zeyaa", "zeyla", "zeyzey", "zeyzeyzey"
1734 ///
1735 /// **Note**: This will only search members that are cached. If you want to search all members
1736 /// in the guild via the Http API, use [`Self::search_members`].
1737 #[must_use]
1738 pub fn members_starting_with(
1739 &self,
1740 prefix: &str,
1741 case_sensitive: bool,
1742 sorted: bool,
1743 ) -> Vec<(&Member, String)> {
1744 fn starts_with(name: &str, prefix: &str, case_sensitive: bool) -> bool {
1745 if case_sensitive {
1746 name.starts_with(prefix)
1747 } else {
1748 name.to_lowercase().starts_with(&prefix.to_lowercase())
1749 }
1750 }
1751
1752 let mut members = self
1753 .members
1754 .values()
1755 .filter_map(|member| {
1756 let username = &member.user.name;
1757
1758 if starts_with(username, prefix, case_sensitive) {
1759 Some((member, username.clone()))
1760 } else {
1761 match &member.nick {
1762 Some(nick) => starts_with(nick, prefix, case_sensitive)
1763 .then(|| (member, nick.clone())),
1764 None => None,
1765 }
1766 }
1767 })
1768 .collect::<Vec<(&Member, String)>>();
1769
1770 if sorted {
1771 members.sort_by(|a, b| closest_to_origin(prefix, &a.1[..], &b.1[..]));
1772 }
1773
1774 members
1775 }
1776
1777 /// Retrieves all [`Member`] containing a given [`String`] as either username or nick, with a
1778 /// priority on username.
1779 ///
1780 /// If the substring is "yla", following results are possible:
1781 /// - "zeyla", "meiyla", "yladenisyla"
1782 ///
1783 /// If 'case_sensitive' is false, the following are not found:
1784 /// - "zeYLa", "meiyLa", "LYAdenislyA"
1785 ///
1786 /// `sorted` decides whether the best early match of the search-term should be the criteria to
1787 /// sort the result. It will look at the account name first, if that does not fit the
1788 /// search-criteria `substring`, the display-name will be considered.
1789 ///
1790 /// For the `substring` "zey" and the unsorted result:
1791 /// - "azey", "zey", "zeyla", "zeylaa", "zeyzeyzey"
1792 ///
1793 /// It would be sorted:
1794 /// - "zey", "azey", "zeyla", "zeylaa", "zeyzeyzey"
1795 ///
1796 /// **Note**: Due to two fields of a [`Member`] being candidates for the searched field,
1797 /// setting `sorted` to `true` will result in an overhead, as both fields have to be considered
1798 /// again for sorting.
1799 ///
1800 /// **Note**: This will only search members that are cached. If you want to search all members
1801 /// in the guild via the Http API, use [`Self::search_members`].
1802 #[must_use]
1803 pub fn members_containing(
1804 &self,
1805 substring: &str,
1806 case_sensitive: bool,
1807 sorted: bool,
1808 ) -> Vec<(&Member, String)> {
1809 let mut members = self
1810 .members
1811 .values()
1812 .filter_map(|member| {
1813 let username = &member.user.name;
1814
1815 if contains(username, substring, case_sensitive) {
1816 Some((member, username.clone()))
1817 } else {
1818 match &member.nick {
1819 Some(nick) => contains(nick, substring, case_sensitive)
1820 .then(|| (member, nick.clone())),
1821 None => None,
1822 }
1823 }
1824 })
1825 .collect::<Vec<(&Member, String)>>();
1826
1827 if sorted {
1828 members.sort_by(|a, b| closest_to_origin(substring, &a.1[..], &b.1[..]));
1829 }
1830
1831 members
1832 }
1833
1834 /// Retrieves a tuple of [`Member`]s containing a given [`String`] in their username as the
1835 /// first field and the name used for sorting as the second field.
1836 ///
1837 /// If the substring is "yla", following results are possible:
1838 /// - "zeyla", "meiyla", "yladenisyla"
1839 ///
1840 /// If 'case_sensitive' is false, the following are not found:
1841 /// - "zeYLa", "meiyLa", "LYAdenislyA"
1842 ///
1843 /// `sort` decides whether the best early match of the search-term should be the criteria to
1844 /// sort the result.
1845 ///
1846 /// For the `substring` "zey" and the unsorted result:
1847 /// - "azey", "zey", "zeyla", "zeylaa", "zeyzeyzey"
1848 ///
1849 /// It would be sorted:
1850 /// - "zey", "azey", "zeyla", "zeylaa", "zeyzeyzey"
1851 ///
1852 /// **Note**: This will only search members that are cached. If you want to search all members
1853 /// in the guild via the Http API, use [`Self::search_members`].
1854 #[must_use]
1855 pub fn members_username_containing(
1856 &self,
1857 substring: &str,
1858 case_sensitive: bool,
1859 sorted: bool,
1860 ) -> Vec<(&Member, String)> {
1861 let mut members = self
1862 .members
1863 .values()
1864 .filter_map(|member| {
1865 let name = &member.user.name;
1866 contains(name, substring, case_sensitive).then(|| (member, name.clone()))
1867 })
1868 .collect::<Vec<(&Member, String)>>();
1869
1870 if sorted {
1871 members.sort_by(|a, b| closest_to_origin(substring, &a.1[..], &b.1[..]));
1872 }
1873
1874 members
1875 }
1876
1877 /// Retrieves all [`Member`] containing a given [`String`] in their nick.
1878 ///
1879 /// If the substring is "yla", following results are possible:
1880 /// - "zeyla", "meiyla", "yladenisyla"
1881 ///
1882 /// If 'case_sensitive' is false, the following are not found:
1883 /// - "zeYLa", "meiyLa", "LYAdenislyA"
1884 ///
1885 /// `sort` decides whether the best early match of the search-term should be the criteria to
1886 /// sort the result.
1887 ///
1888 /// For the `substring` "zey" and the unsorted result:
1889 /// - "azey", "zey", "zeyla", "zeylaa", "zeyzeyzey"
1890 ///
1891 /// It would be sorted:
1892 /// - "zey", "azey", "zeyla", "zeylaa", "zeyzeyzey"
1893 ///
1894 /// **Note**: Instead of panicking, when sorting does not find a nick, the username will be
1895 /// used (this should never happen).
1896 ///
1897 /// **Note**: This will only search members that are cached. If you want to search all members
1898 /// in the guild via the Http API, use [`Self::search_members`].
1899 #[must_use]
1900 pub fn members_nick_containing(
1901 &self,
1902 substring: &str,
1903 case_sensitive: bool,
1904 sorted: bool,
1905 ) -> Vec<(&Member, String)> {
1906 let mut members = self
1907 .members
1908 .values()
1909 .filter_map(|member| {
1910 let nick = member.nick.as_ref().unwrap_or(&member.user.name);
1911 contains(nick, substring, case_sensitive).then(|| (member, nick.clone()))
1912 })
1913 .collect::<Vec<(&Member, String)>>();
1914
1915 if sorted {
1916 members.sort_by(|a, b| closest_to_origin(substring, &a.1[..], &b.1[..]));
1917 }
1918
1919 members
1920 }
1921
1922 /// Calculate a [`Member`]'s permissions in the guild.
1923 ///
1924 /// You likely want to use Guild::user_permissions_in instead as this function does not consider
1925 /// permission overwrites.
1926 #[inline]
1927 #[must_use]
1928 pub fn member_permissions(&self, member: &Member) -> Permissions {
1929 Self::user_permissions_in_(
1930 None,
1931 member.user.id,
1932 &member.roles,
1933 self.id,
1934 &self.roles,
1935 self.owner_id,
1936 )
1937 }
1938
1939 /// Calculate a [`PartialMember`]'s permissions in the guild.
1940 ///
1941 /// You likely want to use Guild::partial_member_permissions_in instead as this function does
1942 /// not consider permission overwrites.
1943 ///
1944 /// # Panics
1945 ///
1946 /// Panics if the passed [`UserId`] does not match the [`PartialMember`] id, if user is Some.
1947 #[inline]
1948 #[must_use]
1949 pub fn partial_member_permissions(
1950 &self,
1951 member_id: UserId,
1952 member: &PartialMember,
1953 ) -> Permissions {
1954 if let Some(user) = &member.user {
1955 assert_eq!(user.id, member_id, "User::id does not match provided PartialMember");
1956 }
1957
1958 Self::user_permissions_in_(
1959 None,
1960 member_id,
1961 &member.roles,
1962 self.id,
1963 &self.roles,
1964 self.owner_id,
1965 )
1966 }
1967
1968 /// Moves a member to a specific voice channel.
1969 ///
1970 /// Requires the [Move Members] permission.
1971 ///
1972 /// # Errors
1973 ///
1974 /// Returns an [`Error::Http`] if the current user lacks permission, or if the member is not
1975 /// currently in a voice channel for this [`Guild`].
1976 ///
1977 /// [Move Members]: Permissions::MOVE_MEMBERS
1978 #[inline]
1979 pub async fn move_member(
1980 &self,
1981 cache_http: impl CacheHttp,
1982 user_id: impl Into<UserId>,
1983 channel_id: impl Into<ChannelId>,
1984 ) -> Result<Member> {
1985 self.id.move_member(cache_http, user_id, channel_id).await
1986 }
1987
1988 /// Calculate a [`Member`]'s permissions in a given channel in the guild.
1989 #[inline]
1990 #[must_use]
1991 pub fn user_permissions_in(&self, channel: &GuildChannel, member: &Member) -> Permissions {
1992 Self::user_permissions_in_(
1993 Some(channel),
1994 member.user.id,
1995 &member.roles,
1996 self.id,
1997 &self.roles,
1998 self.owner_id,
1999 )
2000 }
2001
2002 /// Calculate a [`PartialMember`]'s permissions in a given channel in a guild.
2003 ///
2004 /// # Panics
2005 ///
2006 /// Panics if the passed [`UserId`] does not match the [`PartialMember`] id, if user is Some.
2007 #[must_use]
2008 pub fn partial_member_permissions_in(
2009 &self,
2010 channel: &GuildChannel,
2011 member_id: UserId,
2012 member: &PartialMember,
2013 ) -> Permissions {
2014 if let Some(user) = &member.user {
2015 assert_eq!(user.id, member_id, "User::id does not match provided PartialMember");
2016 }
2017
2018 Self::user_permissions_in_(
2019 Some(channel),
2020 member_id,
2021 &member.roles,
2022 self.id,
2023 &self.roles,
2024 self.owner_id,
2025 )
2026 }
2027
2028 /// Helper function that can also be used from [`PartialGuild`].
2029 pub(crate) fn user_permissions_in_(
2030 channel: Option<&GuildChannel>,
2031 member_user_id: UserId,
2032 member_roles: &[RoleId],
2033 guild_id: GuildId,
2034 guild_roles: &HashMap<RoleId, Role>,
2035 guild_owner_id: UserId,
2036 ) -> Permissions {
2037 let mut everyone_allow_overwrites = Permissions::empty();
2038 let mut everyone_deny_overwrites = Permissions::empty();
2039 let mut roles_allow_overwrites = Vec::new();
2040 let mut roles_deny_overwrites = Vec::new();
2041 let mut member_allow_overwrites = Permissions::empty();
2042 let mut member_deny_overwrites = Permissions::empty();
2043
2044 if let Some(channel) = channel {
2045 for overwrite in &channel.permission_overwrites {
2046 match overwrite.kind {
2047 PermissionOverwriteType::Member(user_id) => {
2048 if member_user_id == user_id {
2049 member_allow_overwrites = overwrite.allow;
2050 member_deny_overwrites = overwrite.deny;
2051 }
2052 },
2053 PermissionOverwriteType::Role(role_id) => {
2054 if role_id.get() == guild_id.get() {
2055 everyone_allow_overwrites = overwrite.allow;
2056 everyone_deny_overwrites = overwrite.deny;
2057 } else if member_roles.contains(&role_id) {
2058 roles_allow_overwrites.push(overwrite.allow);
2059 roles_deny_overwrites.push(overwrite.deny);
2060 }
2061 },
2062 }
2063 }
2064 }
2065
2066 calculate_permissions(CalculatePermissions {
2067 is_guild_owner: member_user_id == guild_owner_id,
2068 everyone_permissions: if let Some(role) = guild_roles.get(&RoleId::new(guild_id.get()))
2069 {
2070 role.permissions
2071 } else {
2072 error!("@everyone role missing in {}", guild_id);
2073 Permissions::empty()
2074 },
2075 user_roles_permissions: member_roles
2076 .iter()
2077 .map(|role_id| {
2078 if let Some(role) = guild_roles.get(role_id) {
2079 role.permissions
2080 } else {
2081 warn!(
2082 "{} on {} has non-existent role {:?}",
2083 member_user_id, guild_id, role_id
2084 );
2085 Permissions::empty()
2086 }
2087 })
2088 .collect(),
2089 everyone_allow_overwrites,
2090 everyone_deny_overwrites,
2091 roles_allow_overwrites,
2092 roles_deny_overwrites,
2093 member_allow_overwrites,
2094 member_deny_overwrites,
2095 })
2096 }
2097
2098 /// Calculate a [`Role`]'s permissions in a given channel in the guild.
2099 ///
2100 /// # Errors
2101 ///
2102 /// Will return an [`Error::Model`] if the [`Role`] or [`Channel`] is not from this [`Guild`].
2103 #[inline]
2104 #[deprecated = "this function ignores other roles the user may have as well as user-specific permissions; use user_permissions_in instead"]
2105 pub fn role_permissions_in(&self, channel: &GuildChannel, role: &Role) -> Result<Permissions> {
2106 Self::role_permissions_in_(channel, role, self.id)
2107 }
2108
2109 /// Helper function that can also be used from [`PartialGuild`].
2110 pub(crate) fn role_permissions_in_(
2111 channel: &GuildChannel,
2112 role: &Role,
2113 guild_id: GuildId,
2114 ) -> Result<Permissions> {
2115 // Fail if the role or channel is not from this guild.
2116 if role.guild_id != guild_id || channel.guild_id != guild_id {
2117 return Err(Error::Model(ModelError::WrongGuild));
2118 }
2119
2120 let mut permissions = role.permissions;
2121
2122 if permissions.contains(Permissions::ADMINISTRATOR) {
2123 return Ok(Self::remove_unnecessary_voice_permissions(channel, Permissions::all()));
2124 }
2125
2126 for overwrite in &channel.permission_overwrites {
2127 if let PermissionOverwriteType::Role(permissions_role_id) = overwrite.kind {
2128 if permissions_role_id == role.id {
2129 permissions = (permissions & !overwrite.deny) | overwrite.allow;
2130
2131 break;
2132 }
2133 }
2134 }
2135
2136 Self::remove_unusable_permissions(&mut permissions);
2137
2138 Ok(permissions)
2139 }
2140
2141 /// Retrieves the count of the number of [`Member`]s that would be pruned with the number of
2142 /// given days.
2143 ///
2144 /// See the documentation on [`GuildPrune`] for more information.
2145 ///
2146 /// **Note**: Requires the [Kick Members] permission.
2147 ///
2148 /// # Errors
2149 ///
2150 /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`] if the current user
2151 /// does not have permission to kick members.
2152 ///
2153 /// Otherwise may return [`Error::Http`] if the current user does not have permission. Can also
2154 /// return [`Error::Json`] if there is an error in deserializing the API response.
2155 ///
2156 /// [Kick Members]: Permissions::KICK_MEMBERS
2157 /// [`Error::Http`]: crate::error::Error::Http
2158 /// [`Error::Json`]: crate::error::Error::Json
2159 pub async fn prune_count(&self, cache_http: impl CacheHttp, days: u8) -> Result<GuildPrune> {
2160 #[cfg(feature = "cache")]
2161 {
2162 if let Some(cache) = cache_http.cache() {
2163 self.require_perms(cache, Permissions::KICK_MEMBERS)?;
2164 }
2165 }
2166
2167 self.id.prune_count(cache_http.http(), days).await
2168 }
2169
2170 pub(crate) fn remove_unusable_permissions(permissions: &mut Permissions) {
2171 // No SEND_MESSAGES => no message-sending-related actions
2172 // If the member does not have the `SEND_MESSAGES` permission, then throw out message-able
2173 // permissions.
2174 if !permissions.contains(Permissions::SEND_MESSAGES) {
2175 *permissions &= !(Permissions::SEND_TTS_MESSAGES
2176 | Permissions::MENTION_EVERYONE
2177 | Permissions::EMBED_LINKS
2178 | Permissions::ATTACH_FILES);
2179 }
2180
2181 // If the permission does not have the `VIEW_CHANNEL` permission, then throw out actionable
2182 // permissions.
2183 if !permissions.contains(Permissions::VIEW_CHANNEL) {
2184 *permissions &= !(Permissions::KICK_MEMBERS
2185 | Permissions::BAN_MEMBERS
2186 | Permissions::ADMINISTRATOR
2187 | Permissions::MANAGE_GUILD
2188 | Permissions::CHANGE_NICKNAME
2189 | Permissions::MANAGE_NICKNAMES);
2190 }
2191 }
2192
2193 pub(crate) fn remove_unnecessary_voice_permissions(
2194 channel: &GuildChannel,
2195 mut permissions: Permissions,
2196 ) -> Permissions {
2197 // If this is a text channel, then throw out voice permissions.
2198 if channel.kind == ChannelType::Text {
2199 permissions &= !(Permissions::CONNECT
2200 | Permissions::SPEAK
2201 | Permissions::MUTE_MEMBERS
2202 | Permissions::DEAFEN_MEMBERS
2203 | Permissions::MOVE_MEMBERS
2204 | Permissions::USE_VAD
2205 | Permissions::STREAM);
2206 }
2207
2208 permissions
2209 }
2210
2211 /// Re-orders the channels of the guild.
2212 ///
2213 /// Although not required, you should specify all channels' positions, regardless of whether
2214 /// they were updated. Otherwise, positioning can sometimes get weird.
2215 ///
2216 /// **Note**: Requires the [Manage Channels] permission.
2217 ///
2218 /// # Errors
2219 ///
2220 /// Returns an [`Error::Http`] if the current user is lacking permission.
2221 ///
2222 /// [Manage Channels]: Permissions::MANAGE_CHANNELS
2223 #[inline]
2224 pub async fn reorder_channels(
2225 &self,
2226 http: impl AsRef<Http>,
2227 channels: impl IntoIterator<Item = (ChannelId, u64)>,
2228 ) -> Result<()> {
2229 self.id.reorder_channels(http, channels).await
2230 }
2231
2232 /// Returns a list of [`Member`]s in a [`Guild`] whose username or nickname starts with a
2233 /// provided string.
2234 ///
2235 /// Optionally pass in the `limit` to limit the number of results. Minimum value is 1, maximum
2236 /// and default value is 1000.
2237 ///
2238 /// **Note**: Queries are case insensitive.
2239 ///
2240 /// # Errors
2241 ///
2242 /// Returns an [`Error::Http`] if the API returns an error.
2243 #[inline]
2244 pub async fn search_members(
2245 &self,
2246 http: impl AsRef<Http>,
2247 query: &str,
2248 limit: Option<u64>,
2249 ) -> Result<Vec<Member>> {
2250 self.id.search_members(http, query, limit).await
2251 }
2252
2253 /// Fetches a specified scheduled event in the guild, by Id. If `with_user_count` is set to
2254 /// `true`, then the `user_count` field will be populated, indicating the number of users
2255 /// interested in the event.
2256 ///
2257 /// **Note**: Requires the [View Channel] permission for the channel associated with the event.
2258 ///
2259 /// # Errors
2260 ///
2261 /// Returns [`Error::Http`] if the current user lacks permission, or if the provided id is
2262 /// invalid.
2263 ///
2264 /// [View Channel]: Permissions::VIEW_CHANNEL
2265 pub async fn scheduled_event(
2266 &self,
2267 http: impl AsRef<Http>,
2268 event_id: impl Into<ScheduledEventId>,
2269 with_user_count: bool,
2270 ) -> Result<ScheduledEvent> {
2271 self.id.scheduled_event(http, event_id, with_user_count).await
2272 }
2273
2274 /// Fetches a list of all scheduled events in the guild. If `with_user_count` is set to `true`,
2275 /// then each event returned will have its `user_count` field populated.
2276 ///
2277 /// **Note**: Requires the [View Channel] permission at the guild level.
2278 ///
2279 /// # Errors
2280 ///
2281 /// Returns [`Error::Http`] if the current user lacks permission.
2282 ///
2283 /// [View Channel]: Permissions::VIEW_CHANNEL
2284 pub async fn scheduled_events(
2285 &self,
2286 http: impl AsRef<Http>,
2287 with_user_count: bool,
2288 ) -> Result<Vec<ScheduledEvent>> {
2289 self.id.scheduled_events(http, with_user_count).await
2290 }
2291
2292 /// Fetches a list of interested users for the specified event.
2293 ///
2294 /// If `limit` is left unset, by default at most 100 users are returned.
2295 ///
2296 /// **Note**: Requires the [View Channel] permission for the channel associated with the event.
2297 ///
2298 /// # Errors
2299 ///
2300 /// Returns [`Error::Http`] if the current user lacks permission, or if the provided Id is
2301 /// invalid.
2302 ///
2303 /// [View Channel]: Permissions::VIEW_CHANNEL
2304 pub async fn scheduled_event_users(
2305 &self,
2306 http: impl AsRef<Http>,
2307 event_id: impl Into<ScheduledEventId>,
2308 limit: Option<u64>,
2309 ) -> Result<Vec<ScheduledEventUser>> {
2310 self.id.scheduled_event_users(http, event_id, limit).await
2311 }
2312
2313 /// Fetches a list of interested users for the specified event, with additional options and
2314 /// filtering. See [`Http::get_scheduled_event_users`] for details.
2315 ///
2316 /// **Note**: Requires the [View Channel] permission for the channel associated with the event.
2317 ///
2318 /// # Errors
2319 ///
2320 /// Returns [`Error::Http`] if the current user lacks permission, or if the provided Id is
2321 /// invalid.
2322 ///
2323 /// [View Channel]: Permissions::VIEW_CHANNEL
2324 pub async fn scheduled_event_users_optioned(
2325 &self,
2326 http: impl AsRef<Http>,
2327 event_id: impl Into<ScheduledEventId>,
2328 limit: Option<u64>,
2329 target: Option<UserPagination>,
2330 with_member: Option<bool>,
2331 ) -> Result<Vec<ScheduledEventUser>> {
2332 self.id.scheduled_event_users_optioned(http, event_id, limit, target, with_member).await
2333 }
2334
2335 /// Returns the Id of the shard associated with the guild.
2336 ///
2337 /// When the cache is enabled this will automatically retrieve the total number of shards.
2338 ///
2339 /// **Note**: When the cache is enabled, this function unlocks the cache to retrieve the total
2340 /// number of shards in use. If you already have the total, consider using [`utils::shard_id`].
2341 ///
2342 /// [`utils::shard_id`]: crate::utils::shard_id
2343 #[cfg(all(feature = "cache", feature = "utils"))]
2344 #[inline]
2345 pub fn shard_id(&self, cache: impl AsRef<Cache>) -> u32 {
2346 self.id.shard_id(&cache)
2347 }
2348
2349 /// Returns the Id of the shard associated with the guild.
2350 ///
2351 /// When the cache is enabled this will automatically retrieve the total number of shards.
2352 ///
2353 /// When the cache is not enabled, the total number of shards being used will need to be
2354 /// passed.
2355 ///
2356 /// # Examples
2357 ///
2358 /// Retrieve the Id of the shard for a guild with Id `81384788765712384`, using 17 shards:
2359 ///
2360 /// ```rust,ignore
2361 /// use serenity::utils;
2362 ///
2363 /// // assumes a `guild` has already been bound
2364 ///
2365 /// assert_eq!(guild.shard_id(17), 7);
2366 /// ```
2367 #[cfg(all(feature = "utils", not(feature = "cache")))]
2368 #[inline]
2369 #[must_use]
2370 pub fn shard_id(&self, shard_count: u32) -> u32 {
2371 self.id.shard_id(shard_count)
2372 }
2373
2374 /// Returns the formatted URL of the guild's splash image, if one exists.
2375 #[must_use]
2376 pub fn splash_url(&self) -> Option<String> {
2377 self.splash.as_ref().map(|splash| cdn!("/splashes/{}/{}.webp?size=4096", self.id, splash))
2378 }
2379
2380 /// Starts an integration sync for the given integration Id.
2381 ///
2382 /// Requires the [Manage Guild] permission.
2383 ///
2384 /// # Errors
2385 ///
2386 /// Returns an [`Error::Http`] if the current user does not have permission, or if an
2387 /// [`Integration`] with that Id does not exist.
2388 ///
2389 /// [Manage Guild]: Permissions::MANAGE_GUILD
2390 #[inline]
2391 pub async fn start_integration_sync(
2392 &self,
2393 http: impl AsRef<Http>,
2394 integration_id: impl Into<IntegrationId>,
2395 ) -> Result<()> {
2396 self.id.start_integration_sync(http, integration_id).await
2397 }
2398
2399 /// Starts a prune of [`Member`]s.
2400 ///
2401 /// See the documentation on [`GuildPrune`] for more information.
2402 ///
2403 /// **Note**: Requires [Kick Members] and [Manage Guild] permissions.
2404 ///
2405 /// # Errors
2406 ///
2407 /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`] if the current user
2408 /// does not have permission to kick members.
2409 ///
2410 /// Otherwise will return [`Error::Http`] if the current user does not have permission.
2411 ///
2412 /// Can also return an [`Error::Json`] if there is an error deserializing the API response.
2413 ///
2414 /// [Kick Members]: Permissions::KICK_MEMBERS
2415 /// [Manage Guild]: Permissions::MANAGE_GUILD
2416 /// [`Error::Http`]: crate::error::Error::Http
2417 /// [`Error::Json`]: crate::error::Error::Json
2418 pub async fn start_prune(&self, cache_http: impl CacheHttp, days: u8) -> Result<GuildPrune> {
2419 #[cfg(feature = "cache")]
2420 {
2421 if let Some(cache) = cache_http.cache() {
2422 self.require_perms(cache, Permissions::KICK_MEMBERS | Permissions::MANAGE_GUILD)?;
2423 }
2424 }
2425
2426 self.id.start_prune(cache_http.http(), days).await
2427 }
2428
2429 /// Unbans the given [`User`] from the guild.
2430 ///
2431 /// **Note**: Requires the [Ban Members] permission.
2432 ///
2433 /// # Errors
2434 ///
2435 /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`] if the current user
2436 /// does not have permission to perform bans.
2437 ///
2438 /// Otherwise will return an [`Error::Http`] if the current user does not have permission.
2439 ///
2440 /// [Ban Members]: Permissions::BAN_MEMBERS
2441 pub async fn unban(
2442 &self,
2443 cache_http: impl CacheHttp,
2444 user_id: impl Into<UserId>,
2445 ) -> Result<()> {
2446 #[cfg(feature = "cache")]
2447 {
2448 if let Some(cache) = cache_http.cache() {
2449 self.require_perms(cache, Permissions::BAN_MEMBERS)?;
2450 }
2451 }
2452
2453 self.id.unban(cache_http.http(), user_id).await
2454 }
2455
2456 /// Retrieve's the guild's vanity URL.
2457 ///
2458 /// **Note**: Requires the [Manage Guild] permission.
2459 ///
2460 /// [Manage Guild]: Permissions::MANAGE_GUILD
2461 ///
2462 /// # Errors
2463 ///
2464 /// Will return [`Error::Http`] if the current user is lacking permissions. Can also return an
2465 /// [`Error::Json`] if there is an error deserializing the API response.
2466 #[inline]
2467 pub async fn vanity_url(&self, http: impl AsRef<Http>) -> Result<String> {
2468 self.id.vanity_url(http).await
2469 }
2470
2471 /// Retrieves the guild's webhooks.
2472 ///
2473 /// **Note**: Requires the [Manage Webhooks] permission.
2474 ///
2475 /// [Manage Webhooks]: Permissions::MANAGE_WEBHOOKS
2476 ///
2477 /// # Errors
2478 ///
2479 /// Will return an [`Error::Http`] if the current user is lacking permissions. Can also return
2480 /// an [`Error::Json`] if there is an error deserializing the API response.
2481 #[inline]
2482 pub async fn webhooks(&self, http: impl AsRef<Http>) -> Result<Vec<Webhook>> {
2483 self.id.webhooks(http).await
2484 }
2485
2486 /// Obtain a reference to a role by its name.
2487 ///
2488 /// **Note**: If two or more roles have the same name, obtained reference will be one of them.
2489 ///
2490 /// # Examples
2491 ///
2492 /// Obtain a reference to a [`Role`] by its name.
2493 ///
2494 /// ```rust,no_run
2495 /// # use serenity::model::prelude::*;
2496 /// # use serenity::prelude::*;
2497 /// # struct Handler;
2498 ///
2499 /// #[serenity::async_trait]
2500 /// #[cfg(all(feature = "cache", feature = "client"))]
2501 /// impl EventHandler for Handler {
2502 /// async fn message(&self, ctx: Context, msg: Message) {
2503 /// if let Some(guild_id) = msg.guild_id {
2504 /// if let Some(guild) = guild_id.to_guild_cached(&ctx) {
2505 /// if let Some(role) = guild.role_by_name("role_name") {
2506 /// println!("{:?}", role);
2507 /// }
2508 /// }
2509 /// }
2510 /// }
2511 /// }
2512 /// ```
2513 #[must_use]
2514 pub fn role_by_name(&self, role_name: &str) -> Option<&Role> {
2515 self.roles.values().find(|role| role_name == role.name)
2516 }
2517
2518 /// Returns a builder which can be awaited to obtain a message or stream of messages in this
2519 /// guild.
2520 #[cfg(feature = "collector")]
2521 pub fn await_reply(&self, shard_messenger: impl AsRef<ShardMessenger>) -> MessageCollector {
2522 MessageCollector::new(shard_messenger).guild_id(self.id)
2523 }
2524
2525 /// Same as [`Self::await_reply`].
2526 #[cfg(feature = "collector")]
2527 pub fn await_replies(&self, shard_messenger: impl AsRef<ShardMessenger>) -> MessageCollector {
2528 self.await_reply(shard_messenger)
2529 }
2530
2531 /// Returns a builder which can be awaited to obtain a message or stream of reactions sent in
2532 /// this guild.
2533 #[cfg(feature = "collector")]
2534 pub fn await_reaction(&self, shard_messenger: impl AsRef<ShardMessenger>) -> ReactionCollector {
2535 ReactionCollector::new(shard_messenger).guild_id(self.id)
2536 }
2537
2538 /// Same as [`Self::await_reaction`].
2539 #[cfg(feature = "collector")]
2540 pub fn await_reactions(
2541 &self,
2542 shard_messenger: impl AsRef<ShardMessenger>,
2543 ) -> ReactionCollector {
2544 self.await_reaction(shard_messenger)
2545 }
2546
2547 /// Gets the guild active threads.
2548 ///
2549 /// # Errors
2550 ///
2551 /// Returns [`Error::Http`] if there is an error in the deserialization, or if the bot issuing
2552 /// the request is not in the guild.
2553 pub async fn get_active_threads(&self, http: impl AsRef<Http>) -> Result<ThreadsData> {
2554 self.id.get_active_threads(http).await
2555 }
2556
2557 /// Gets a soundboard sound from the guild.
2558 ///
2559 /// # Errors
2560 ///
2561 /// Returns [`Error::Http`] if there is an error in the deserialization, or if the bot issuing
2562 /// the request is not in the guild.
2563 pub async fn get_soundboard(
2564 self,
2565 http: impl AsRef<Http>,
2566 sound_id: SoundId,
2567 ) -> Result<Soundboard> {
2568 self.id.get_soundboard(http, sound_id).await
2569 }
2570
2571 /// Gets all soundboard sounds from the guild.
2572 ///
2573 /// # Errors
2574 ///
2575 /// Returns [`Error::Http`] if there is an error in the deserialization, or if the bot issuing
2576 /// the request is not in the guild.
2577 pub async fn get_soundboards(self, http: impl AsRef<Http>) -> Result<Vec<Soundboard>> {
2578 self.id.get_soundboards(http).await
2579 }
2580
2581 /// Creates a soundboard sound for the guild.
2582 ///
2583 /// # Errors
2584 ///
2585 /// See [`CreateSoundboard::execute`] for a list of possible errors.
2586 ///
2587 /// [`CreateSoundboard::execute`]: ../../builder/struct.CreateSoundboard.html#method.execute
2588 pub async fn create_soundboard(
2589 self,
2590 cache_http: impl CacheHttp,
2591 builder: CreateSoundboard<'_>,
2592 ) -> Result<Soundboard> {
2593 self.id.create_soundboard(cache_http, builder).await
2594 }
2595
2596 /// Edits a soundboard sound for the guild.
2597 ///
2598 /// # Errors
2599 ///
2600 /// See [`EditSoundboard::execute`] for a list of possible errors.
2601 ///
2602 /// [`EditSoundboard::execute`]: ../../builder/struct.EditSoundboard.html#method.execute
2603 pub async fn edit_soundboard(
2604 self,
2605 cache_http: impl CacheHttp,
2606 sound_id: SoundId,
2607 builder: EditSoundboard<'_>,
2608 ) -> Result<Soundboard> {
2609 self.id.edit_soundboard(cache_http, sound_id, builder).await
2610 }
2611
2612 /// Deletes a soundboard sound for the guild.
2613 ///
2614 /// # Errors
2615 ///
2616 /// Returns [`Error::Http`] if the current user lacks permission, or if a
2617 /// soundboard sound with that Id does not exist.
2618 pub async fn delete_soundboard(
2619 self,
2620 http: impl AsRef<Http>,
2621 sound_id: SoundId,
2622 audit_log_reason: Option<&str>,
2623 ) -> Result<()> {
2624 self.id.delete_soundboard(http, sound_id, audit_log_reason).await
2625 }
2626
2627 /// Edits the guild incident actions
2628 ///
2629 /// **Note**: Requires the [Manage Guild] permission.
2630 ///
2631 /// [Manage Guild]: Permissions::MANAGE_GUILD
2632 ///
2633 /// # Errors
2634 ///
2635 /// Returns [`Error::Http`] if invalid data is given. See [Discord's docs] for more details.
2636 ///
2637 /// May also return [`Error::Json`] if there is an error in deserializing the API response.
2638 ///
2639 /// [Discord's docs]: https://discord.com/developers/docs/resources/guild#modify-guild-incident-actions
2640 pub async fn edit_guild_incident_actions(
2641 self,
2642 http: &Http,
2643 guild_id: GuildId,
2644 builder: EditGuildIncidentActions,
2645 ) -> Result<IncidentsData> {
2646 builder.execute(http, guild_id).await
2647 }
2648}
2649
2650#[cfg(feature = "model")]
2651struct CalculatePermissions {
2652 /// Whether the guild member is the guild owner
2653 pub is_guild_owner: bool,
2654 /// Base permissions given to @everyone (guild level)
2655 pub everyone_permissions: Permissions,
2656 /// Permissions allowed to a user by their roles (guild level)
2657 pub user_roles_permissions: Vec<Permissions>,
2658 /// Overwrites that deny permissions for @everyone (channel level)
2659 pub everyone_allow_overwrites: Permissions,
2660 /// Overwrites that allow permissions for @everyone (channel level)
2661 pub everyone_deny_overwrites: Permissions,
2662 /// Overwrites that deny permissions for specific roles (channel level)
2663 pub roles_allow_overwrites: Vec<Permissions>,
2664 /// Overwrites that allow permissions for specific roles (channel level)
2665 pub roles_deny_overwrites: Vec<Permissions>,
2666 /// Member-specific overwrites that deny permissions (channel level)
2667 pub member_allow_overwrites: Permissions,
2668 /// Member-specific overwrites that allow permissions (channel level)
2669 pub member_deny_overwrites: Permissions,
2670}
2671
2672#[cfg(feature = "model")]
2673impl Default for CalculatePermissions {
2674 fn default() -> Self {
2675 Self {
2676 is_guild_owner: false,
2677 everyone_permissions: Permissions::empty(),
2678 user_roles_permissions: Vec::new(),
2679 everyone_allow_overwrites: Permissions::empty(),
2680 everyone_deny_overwrites: Permissions::empty(),
2681 roles_allow_overwrites: Vec::new(),
2682 roles_deny_overwrites: Vec::new(),
2683 member_allow_overwrites: Permissions::empty(),
2684 member_deny_overwrites: Permissions::empty(),
2685 }
2686 }
2687}
2688
2689/// Translated from the pseudo code at https://discord.com/developers/docs/topics/permissions#permission-overwrites
2690///
2691/// The comments within this file refer to the above link
2692#[cfg(feature = "model")]
2693fn calculate_permissions(data: CalculatePermissions) -> Permissions {
2694 if data.is_guild_owner {
2695 return Permissions::all();
2696 }
2697
2698 // 1. Base permissions given to @everyone are applied at a guild level
2699 let mut permissions = data.everyone_permissions;
2700 // 2. Permissions allowed to a user by their roles are applied at a guild level
2701 for role_permission in data.user_roles_permissions {
2702 permissions |= role_permission;
2703 }
2704
2705 if permissions.contains(Permissions::ADMINISTRATOR) {
2706 return Permissions::all();
2707 }
2708
2709 // 3. Overwrites that deny permissions for @everyone are applied at a channel level
2710 permissions &= !data.everyone_deny_overwrites;
2711 // 4. Overwrites that allow permissions for @everyone are applied at a channel level
2712 permissions |= data.everyone_allow_overwrites;
2713
2714 // 5. Overwrites that deny permissions for specific roles are applied at a channel level
2715 let mut role_deny_permissions = Permissions::empty();
2716 for p in data.roles_deny_overwrites {
2717 role_deny_permissions |= p;
2718 }
2719 permissions &= !role_deny_permissions;
2720
2721 // 6. Overwrites that allow permissions for specific roles are applied at a channel level
2722 let mut role_allow_permissions = Permissions::empty();
2723 for p in data.roles_allow_overwrites {
2724 role_allow_permissions |= p;
2725 }
2726 permissions |= role_allow_permissions;
2727
2728 // 7. Member-specific overwrites that deny permissions are applied at a channel level
2729 permissions &= !data.member_deny_overwrites;
2730 // 8. Member-specific overwrites that allow permissions are applied at a channel level
2731 permissions |= data.member_allow_overwrites;
2732
2733 permissions
2734}
2735
2736/// Checks if a `&str` contains another `&str`.
2737#[cfg(feature = "model")]
2738fn contains(haystack: &str, needle: &str, case_sensitive: bool) -> bool {
2739 if case_sensitive {
2740 haystack.contains(needle)
2741 } else {
2742 haystack.to_lowercase().contains(&needle.to_lowercase())
2743 }
2744}
2745
2746/// Takes a `&str` as `origin` and tests if either `word_a` or `word_b` is closer.
2747///
2748/// **Note**: Normally `word_a` and `word_b` are expected to contain `origin` as substring. If not,
2749/// using `closest_to_origin` would sort these the end.
2750#[cfg(feature = "model")]
2751fn closest_to_origin(origin: &str, word_a: &str, word_b: &str) -> std::cmp::Ordering {
2752 let value_a = match word_a.find(origin) {
2753 Some(value) => value + word_a.len(),
2754 None => return std::cmp::Ordering::Greater,
2755 };
2756
2757 let value_b = match word_b.find(origin) {
2758 Some(value) => value + word_b.len(),
2759 None => return std::cmp::Ordering::Less,
2760 };
2761
2762 value_a.cmp(&value_b)
2763}
2764
2765/// A [`Guild`] widget.
2766///
2767/// [Discord docs](https://discord.com/developers/docs/resources/guild#guild-widget-settings-object).
2768#[derive(Clone, Debug, Deserialize, Serialize)]
2769#[non_exhaustive]
2770pub struct GuildWidget {
2771 /// Whether the widget is enabled.
2772 pub enabled: bool,
2773 /// The widget channel id.
2774 pub channel_id: Option<ChannelId>,
2775}
2776
2777/// Representation of the number of members that would be pruned by a guild prune operation.
2778///
2779/// [Discord docs](https://discord.com/developers/docs/resources/guild#get-guild-prune-count).
2780#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
2781#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
2782#[non_exhaustive]
2783pub struct GuildPrune {
2784 /// The number of members that would be pruned by the operation.
2785 pub pruned: u64,
2786}
2787
2788/// Variant of [`Guild`] returned from [`Http::get_guilds`].
2789///
2790/// [Discord docs](https://discord.com/developers/docs/resources/guild#guild-object),
2791/// [subset example](https://discord.com/developers/docs/resources/user#get-current-user-guilds-example-partial-guild).
2792#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
2793#[derive(Clone, Debug, Deserialize, Serialize)]
2794#[non_exhaustive]
2795pub struct GuildInfo {
2796 /// The unique Id of the guild.
2797 ///
2798 /// Can be used to calculate creation date.
2799 pub id: GuildId,
2800 /// The name of the guild.
2801 pub name: String,
2802 /// The hash of the icon of the guild.
2803 ///
2804 /// This can be used to generate a URL to the guild's icon image.
2805 pub icon: Option<ImageHash>,
2806 /// Indicator of whether the current user is the owner.
2807 pub owner: bool,
2808 /// The permissions that the current user has.
2809 pub permissions: Permissions,
2810 /// See [`Guild::features`].
2811 pub features: Vec<String>,
2812}
2813
2814#[cfg(feature = "model")]
2815impl GuildInfo {
2816 /// Returns the formatted URL of the guild's icon, if the guild has an icon.
2817 ///
2818 /// This will produce a WEBP image URL, or GIF if the guild has a GIF icon.
2819 #[must_use]
2820 pub fn icon_url(&self) -> Option<String> {
2821 icon_url(self.id, self.icon.as_ref())
2822 }
2823}
2824
2825#[cfg(feature = "model")]
2826impl InviteGuild {
2827 /// Returns the formatted URL of the guild's splash image, if one exists.
2828 #[must_use]
2829 pub fn splash_url(&self) -> Option<String> {
2830 self.splash.as_ref().map(|splash| cdn!("/splashes/{}/{}.webp?size=4096", self.id, splash))
2831 }
2832}
2833
2834/// Data for an unavailable guild.
2835///
2836/// [Discord docs](https://discord.com/developers/docs/resources/guild#unavailable-guild-object).
2837#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
2838#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
2839#[non_exhaustive]
2840pub struct UnavailableGuild {
2841 /// The Id of the [`Guild`] that may be unavailable.
2842 pub id: GuildId,
2843 /// Indicator of whether the guild is unavailable.
2844 #[serde(default)]
2845 pub unavailable: bool,
2846}
2847
2848enum_number! {
2849 /// Default message notification level for a guild.
2850 ///
2851 /// [Discord docs](https://discord.com/developers/docs/resources/guild#guild-object-default-message-notification-level).
2852 #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Deserialize, Serialize)]
2853 #[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
2854 #[serde(from = "u8", into = "u8")]
2855 #[non_exhaustive]
2856 pub enum DefaultMessageNotificationLevel {
2857 /// Receive notifications for everything.
2858 #[default]
2859 All = 0,
2860 /// Receive only mentions.
2861 Mentions = 1,
2862 _ => Unknown(u8),
2863 }
2864}
2865
2866enum_number! {
2867 /// Setting used to filter explicit messages from members.
2868 ///
2869 /// [Discord docs](https://discord.com/developers/docs/resources/guild#guild-object-explicit-content-filter-level).
2870 #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Deserialize, Serialize)]
2871 #[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
2872 #[serde(from = "u8", into = "u8")]
2873 #[non_exhaustive]
2874 pub enum ExplicitContentFilter {
2875 /// Don't scan any messages.
2876 #[default]
2877 None = 0,
2878 /// Scan messages from members without a role.
2879 WithoutRole = 1,
2880 /// Scan messages sent by all members.
2881 All = 2,
2882 _ => Unknown(u8),
2883 }
2884}
2885
2886enum_number! {
2887 /// Multi-Factor Authentication level for guild moderators.
2888 ///
2889 /// [Discord docs](https://discord.com/developers/docs/resources/guild#guild-object-mfa-level).
2890 #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Deserialize, Serialize)]
2891 #[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
2892 #[serde(from = "u8", into = "u8")]
2893 #[non_exhaustive]
2894 pub enum MfaLevel {
2895 /// MFA is disabled.
2896 #[default]
2897 None = 0,
2898 /// MFA is enabled.
2899 Elevated = 1,
2900 _ => Unknown(u8),
2901 }
2902}
2903
2904enum_number! {
2905 /// The level to set as criteria prior to a user being able to send
2906 /// messages in a [`Guild`].
2907 ///
2908 /// [Discord docs](https://discord.com/developers/docs/resources/guild#guild-object-verification-level).
2909 #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Deserialize, Serialize)]
2910 #[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
2911 #[serde(from = "u8", into = "u8")]
2912 #[non_exhaustive]
2913 pub enum VerificationLevel {
2914 /// Does not require any verification.
2915 #[default]
2916 None = 0,
2917 /// Must have a verified email on the user's Discord account.
2918 Low = 1,
2919 /// Must also be a registered user on Discord for longer than 5 minutes.
2920 Medium = 2,
2921 /// Must also be a member of the guild for longer than 10 minutes.
2922 High = 3,
2923 /// Must have a verified phone on the user's Discord account.
2924 Higher = 4,
2925 _ => Unknown(u8),
2926 }
2927}
2928
2929enum_number! {
2930 /// The [`Guild`] nsfw level.
2931 ///
2932 /// [Discord docs](https://discord.com/developers/docs/resources/guild#guild-object-guild-nsfw-level).
2933 #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Deserialize, Serialize)]
2934 #[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
2935 #[serde(from = "u8", into = "u8")]
2936 #[non_exhaustive]
2937 pub enum NsfwLevel {
2938 /// The nsfw level is not specified.
2939 #[default]
2940 Default = 0,
2941 /// The guild is considered as explicit.
2942 Explicit = 1,
2943 /// The guild is considered as safe.
2944 Safe = 2,
2945 /// The guild is age restricted.
2946 AgeRestricted = 3,
2947 _ => Unknown(u8),
2948 }
2949}
2950
2951enum_number! {
2952 /// The [`Guild`] AFK timeout length.
2953 ///
2954 /// See [AfkMetadata::afk_timeout].
2955 #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Deserialize, Serialize)]
2956 #[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
2957 #[serde(from = "u16", into = "u16")]
2958 #[non_exhaustive]
2959 pub enum AfkTimeout {
2960 OneMinute = 60,
2961 FiveMinutes = 300,
2962 FifteenMinutes = 900,
2963 ThirtyMinutes = 1800,
2964 OneHour = 3600,
2965 _ => Unknown(u16),
2966 }
2967}
2968
2969/// The [`Guild`]'s incident's data.
2970///
2971/// [Discord docs](https://discord.com/developers/docs/resources/guild#incidents-data-object).
2972#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
2973#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
2974#[non_exhaustive]
2975pub struct IncidentsData {
2976 /// The time that invites get enabled again.
2977 pub invites_disabled_until: Option<Timestamp>,
2978 /// The time that dms get enabled again.
2979 pub dms_disabled_until: Option<Timestamp>,
2980 /// The time when elevated dm activity was triggered.
2981 pub dm_spam_detected_at: Option<Timestamp>,
2982 /// The time when raid alerts were triggered.
2983 pub raid_detected_at: Option<Timestamp>,
2984}
2985
2986#[cfg(test)]
2987mod test {
2988 #[cfg(feature = "model")]
2989 mod model {
2990 use std::collections::*;
2991 use std::num::NonZeroU16;
2992
2993 use crate::model::prelude::*;
2994
2995 fn gen_member() -> Member {
2996 Member {
2997 nick: Some("aaaa".to_string()),
2998 user: User {
2999 name: "test".into(),
3000 discriminator: NonZeroU16::new(1432),
3001 ..User::default()
3002 },
3003 ..Default::default()
3004 }
3005 }
3006
3007 fn gen() -> Guild {
3008 let m = gen_member();
3009
3010 Guild {
3011 members: HashMap::from([(m.user.id, m)]),
3012 ..Default::default()
3013 }
3014 }
3015
3016 #[test]
3017 fn member_named_username() {
3018 let guild = gen();
3019 let lhs = guild.member_named("test#1432").unwrap().display_name();
3020
3021 assert_eq!(lhs, gen_member().display_name());
3022 }
3023
3024 #[test]
3025 fn member_named_nickname() {
3026 let guild = gen();
3027 let lhs = guild.member_named("aaaa").unwrap().display_name();
3028
3029 assert_eq!(lhs, gen_member().display_name());
3030 }
3031 }
3032}