Skip to main content

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}