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