twilight_http/client/mod.rs
1mod builder;
2mod connector;
3mod interaction;
4
5pub use self::{builder::ClientBuilder, interaction::InteractionClient};
6
7use crate::request::{
8 application::{
9 emoji::{
10 AddApplicationEmoji, DeleteApplicationEmoji, ListApplicationEmojis,
11 UpdateApplicationEmoji,
12 },
13 monetization::{
14 CreateTestEntitlement, CreateTestEntitlementOwner, DeleteTestEntitlement,
15 GetEntitlements, GetSKUs,
16 },
17 },
18 guild::user::{GetCurrentUserVoiceState, GetUserVoiceState},
19};
20#[allow(deprecated)]
21use crate::{
22 client::connector::Connector,
23 error::{Error, ErrorType},
24 request::{
25 channel::{
26 invite::{CreateInvite, DeleteInvite, GetChannelInvites, GetInvite},
27 message::{
28 CreateMessage, CrosspostMessage, DeleteMessage, DeleteMessages, GetChannelMessages,
29 GetMessage, UpdateMessage,
30 },
31 reaction::{
32 delete_reaction::TargetUser, CreateReaction, DeleteAllReaction, DeleteAllReactions,
33 DeleteReaction, GetReactions, RequestReactionType,
34 },
35 stage::{
36 CreateStageInstance, DeleteStageInstance, GetStageInstance, UpdateStageInstance,
37 },
38 thread::{
39 AddThreadMember, CreateForumThread, CreateThread, CreateThreadFromMessage,
40 GetJoinedPrivateArchivedThreads, GetPrivateArchivedThreads,
41 GetPublicArchivedThreads, GetThreadMember, GetThreadMembers, JoinThread,
42 LeaveThread, RemoveThreadMember, UpdateThread,
43 },
44 webhook::{
45 CreateWebhook, DeleteWebhook, DeleteWebhookMessage, ExecuteWebhook,
46 GetChannelWebhooks, GetWebhook, GetWebhookMessage, UpdateWebhook,
47 UpdateWebhookMessage, UpdateWebhookWithToken,
48 },
49 CreatePin, CreateTypingTrigger, DeleteChannel, DeleteChannelPermission, DeletePin,
50 FollowNewsChannel, GetChannel, GetPins, UpdateChannel, UpdateChannelPermission,
51 },
52 guild::{
53 auto_moderation::{
54 CreateAutoModerationRule, DeleteAutoModerationRule, GetAutoModerationRule,
55 GetGuildAutoModerationRules, UpdateAutoModerationRule,
56 },
57 ban::{CreateBan, DeleteBan, GetBan, GetBans},
58 emoji::{CreateEmoji, DeleteEmoji, GetEmoji, GetEmojis, UpdateEmoji},
59 integration::{DeleteGuildIntegration, GetGuildIntegrations},
60 member::{
61 AddGuildMember, AddRoleToMember, GetGuildMembers, GetMember, RemoveMember,
62 RemoveRoleFromMember, SearchGuildMembers, UpdateGuildMember,
63 },
64 role::{
65 CreateRole, DeleteRole, GetGuildRoles, GetRole, UpdateRole, UpdateRolePositions,
66 },
67 sticker::{
68 CreateGuildSticker, DeleteGuildSticker, GetGuildSticker, GetGuildStickers,
69 UpdateGuildSticker,
70 },
71 update_guild_onboarding::{UpdateGuildOnboarding, UpdateGuildOnboardingFields},
72 user::{UpdateCurrentUserVoiceState, UpdateUserVoiceState},
73 CreateGuild, CreateGuildChannel, CreateGuildPrune, DeleteGuild, GetActiveThreads,
74 GetAuditLog, GetGuild, GetGuildChannels, GetGuildInvites, GetGuildOnboarding,
75 GetGuildPreview, GetGuildPruneCount, GetGuildVanityUrl, GetGuildVoiceRegions,
76 GetGuildWebhooks, GetGuildWelcomeScreen, GetGuildWidget, GetGuildWidgetSettings,
77 UpdateCurrentMember, UpdateGuild, UpdateGuildChannelPositions, UpdateGuildMfa,
78 UpdateGuildWelcomeScreen, UpdateGuildWidgetSettings,
79 },
80 poll::{EndPoll, GetAnswerVoters},
81 scheduled_event::{
82 CreateGuildScheduledEvent, DeleteGuildScheduledEvent, GetGuildScheduledEvent,
83 GetGuildScheduledEventUsers, GetGuildScheduledEvents, UpdateGuildScheduledEvent,
84 },
85 sticker::{GetNitroStickerPacks, GetSticker},
86 template::{
87 CreateGuildFromTemplate, CreateTemplate, DeleteTemplate, GetTemplate, GetTemplates,
88 SyncTemplate, UpdateTemplate,
89 },
90 user::{
91 CreatePrivateChannel, GetCurrentUser, GetCurrentUserConnections,
92 GetCurrentUserGuildMember, GetCurrentUserGuilds, GetUser, LeaveGuild,
93 UpdateCurrentUser,
94 },
95 GetCurrentAuthorizationInformation, GetGateway, GetUserApplicationInfo, GetVoiceRegions,
96 Method, Request, UpdateCurrentUserApplication,
97 },
98 response::ResponseFuture,
99 API_VERSION,
100};
101use http::header::{
102 HeaderMap, HeaderValue, AUTHORIZATION, CONTENT_LENGTH, CONTENT_TYPE, USER_AGENT,
103};
104use http_body_util::Full;
105use hyper::body::Bytes;
106use hyper_util::client::legacy::Client as HyperClient;
107use std::{
108 fmt::{Debug, Formatter, Result as FmtResult},
109 ops::Deref,
110 sync::{
111 atomic::{AtomicBool, Ordering},
112 Arc,
113 },
114 time::Duration,
115};
116use tokio::time;
117use twilight_http_ratelimiting::Ratelimiter;
118use twilight_model::{
119 channel::{message::AllowedMentions, ChannelType},
120 guild::{
121 auto_moderation::AutoModerationEventType, scheduled_event::PrivacyLevel, MfaLevel,
122 RolePosition,
123 },
124 http::{channel_position::Position, permission_overwrite::PermissionOverwrite},
125 id::{
126 marker::{
127 ApplicationMarker, AutoModerationRuleMarker, ChannelMarker, EmojiMarker,
128 EntitlementMarker, GuildMarker, IntegrationMarker, MessageMarker, RoleMarker,
129 ScheduledEventMarker, SkuMarker, StickerMarker, UserMarker, WebhookMarker,
130 },
131 Id,
132 },
133};
134
135const TWILIGHT_USER_AGENT: &str = concat!(
136 "DiscordBot (",
137 env!("CARGO_PKG_HOMEPAGE"),
138 ", ",
139 env!("CARGO_PKG_VERSION"),
140 ") Twilight-rs",
141);
142
143/// Wrapper for an authorization token with a debug implementation that redacts
144/// the string.
145#[derive(Default)]
146struct Token {
147 /// Authorization token that is redacted in the Debug implementation.
148 inner: Box<str>,
149}
150
151impl Token {
152 /// Create a new authorization wrapper.
153 const fn new(token: Box<str>) -> Self {
154 Self { inner: token }
155 }
156}
157
158impl Debug for Token {
159 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
160 f.write_str("<redacted>")
161 }
162}
163
164impl Deref for Token {
165 type Target = str;
166
167 fn deref(&self) -> &Self::Target {
168 &self.inner
169 }
170}
171
172/// Twilight's http client.
173///
174/// Almost all of the client methods require authentication, and as such, the client must be
175/// supplied with a Discord Token. Get yours [here].
176///
177/// # Interactions
178///
179/// HTTP interaction requests may be accessed via the [`Client::interaction`]
180/// method.
181///
182/// # OAuth2
183///
184/// To use Bearer tokens prefix the token with `"Bearer "`, including the space
185/// at the end like so:
186///
187/// ```no_run
188/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
189/// use std::env;
190/// use twilight_http::Client;
191///
192/// let bearer = env::var("BEARER_TOKEN")?;
193/// let token = format!("Bearer {bearer}");
194///
195/// let client = Client::new(token);
196/// # Ok(()) }
197/// ```
198///
199/// # Using the client in multiple tasks
200///
201/// To use a client instance in multiple tasks, consider wrapping it in an
202/// [`std::sync::Arc`] or [`std::rc::Rc`].
203///
204/// # Unauthorized behavior
205///
206/// When the client encounters an Unauthorized response it will take note that
207/// the configured token is invalid. This may occur when the token has been
208/// revoked or expired. When this happens, you must create a new client with the
209/// new token. The client will no longer execute requests in order to
210/// prevent API bans and will always return [`ErrorType::Unauthorized`].
211///
212/// # Examples
213///
214/// Create a client called `client`:
215/// ```no_run
216/// use twilight_http::Client;
217///
218/// # #[tokio::main]
219/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
220/// let client = Client::new("my token".to_owned());
221/// # Ok(()) }
222/// ```
223///
224/// Use [`ClientBuilder`] to create a client called `client`, with a shorter
225/// timeout:
226/// ```no_run
227/// use std::time::Duration;
228/// use twilight_http::Client;
229///
230/// # #[tokio::main]
231/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
232/// let client = Client::builder()
233/// .token("my token".to_owned())
234/// .timeout(Duration::from_secs(5))
235/// .build();
236/// # Ok(()) }
237/// ```
238///
239/// All the examples on this page assume you have already created a client, and have named it
240/// `client`.
241///
242/// [here]: https://discord.com/developers/applications
243#[derive(Debug)]
244pub struct Client {
245 pub(crate) default_allowed_mentions: Option<AllowedMentions>,
246 default_headers: Option<HeaderMap>,
247 http: HyperClient<Connector, Full<Bytes>>,
248 proxy: Option<Box<str>>,
249 ratelimiter: Option<Box<dyn Ratelimiter>>,
250 timeout: Duration,
251 /// Whether the token has been invalidated.
252 ///
253 /// Whether an invalid token is tracked can be configured via
254 /// [`ClientBuilder::remember_invalid_token`].
255 token_invalidated: Option<Arc<AtomicBool>>,
256 token: Option<Token>,
257 use_http: bool,
258}
259
260impl Client {
261 /// Create a new client with a token.
262 pub fn new(token: String) -> Self {
263 ClientBuilder::default().token(token).build()
264 }
265
266 /// Create a new builder to create a client.
267 ///
268 /// Refer to its documentation for more information.
269 pub fn builder() -> ClientBuilder {
270 ClientBuilder::new()
271 }
272
273 /// Retrieve an immutable reference to the token used by the client.
274 ///
275 /// If the initial token provided is not prefixed with `Bot `, it will be, and this method
276 /// reflects that.
277 pub fn token(&self) -> Option<&str> {
278 self.token.as_deref()
279 }
280
281 /// Create an interface for using interactions.
282 ///
283 /// An application ID is required to be passed in to use interactions. The
284 /// ID may be retrieved via [`current_user_application`] and cached for use
285 /// with this method.
286 ///
287 /// # Examples
288 ///
289 /// Retrieve the application ID and then use an interaction request:
290 ///
291 /// ```no_run
292 /// # #[tokio::main]
293 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
294 /// use std::env;
295 /// use twilight_http::Client;
296 ///
297 /// let client = Client::new(env::var("DISCORD_TOKEN")?);
298 ///
299 /// // Cache the application ID for repeated use later in the process.
300 /// let application_id = {
301 /// let response = client.current_user_application().await?;
302 ///
303 /// response.model().await?.id
304 /// };
305 ///
306 /// // Later in the process...
307 /// let commands = client
308 /// .interaction(application_id)
309 /// .global_commands()
310 /// .await?
311 /// .models()
312 /// .await?;
313 ///
314 /// println!("there are {} global commands", commands.len());
315 /// # Ok(()) }
316 /// ```
317 ///
318 /// [`current_user_application`]: Self::current_user_application
319 pub const fn interaction(
320 &self,
321 application_id: Id<ApplicationMarker>,
322 ) -> InteractionClient<'_> {
323 InteractionClient::new(self, application_id)
324 }
325
326 /// Get an immutable reference to the default [`AllowedMentions`] for sent
327 /// messages.
328 pub const fn default_allowed_mentions(&self) -> Option<&AllowedMentions> {
329 self.default_allowed_mentions.as_ref()
330 }
331
332 /// Get the Ratelimiter used by the client internally.
333 ///
334 /// This will return `None` only if ratelimit handling
335 /// has been explicitly disabled in the [`ClientBuilder`].
336 pub fn ratelimiter(&self) -> Option<&dyn Ratelimiter> {
337 self.ratelimiter.as_ref().map(AsRef::as_ref)
338 }
339
340 /// Get an auto moderation rule in a guild.
341 ///
342 /// Requires the [`MANAGE_GUILD`] permission.
343 ///
344 /// [`MANAGE_GUILD`]: twilight_model::guild::Permissions::MANAGE_GUILD
345 pub const fn auto_moderation_rule(
346 &self,
347 guild_id: Id<GuildMarker>,
348 auto_moderation_rule_id: Id<AutoModerationRuleMarker>,
349 ) -> GetAutoModerationRule<'_> {
350 GetAutoModerationRule::new(self, guild_id, auto_moderation_rule_id)
351 }
352
353 /// Get the auto moderation rules in a guild.
354 ///
355 /// Requires the [`MANAGE_GUILD`] permission.
356 ///
357 /// [`MANAGE_GUILD`]: twilight_model::guild::Permissions::MANAGE_GUILD
358 pub const fn auto_moderation_rules(
359 &self,
360 guild_id: Id<GuildMarker>,
361 ) -> GetGuildAutoModerationRules<'_> {
362 GetGuildAutoModerationRules::new(self, guild_id)
363 }
364
365 /// Create an auto moderation rule within a guild.
366 ///
367 /// Requires the [`MANAGE_GUILD`] permission.
368 ///
369 /// # Examples
370 ///
371 /// Create a rule that deletes messages that contain the word "darn":
372 ///
373 /// ```no_run
374 /// # #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> {
375 /// use twilight_http::Client;
376 /// use twilight_model::{guild::auto_moderation::AutoModerationEventType, id::Id};
377 ///
378 /// let client = Client::new("my token".to_owned());
379 ///
380 /// let guild_id = Id::new(1);
381 /// client
382 /// .create_auto_moderation_rule(guild_id, "no darns", AutoModerationEventType::MessageSend)
383 /// .action_block_message()
384 /// .enabled(true)
385 /// .with_keyword(&["darn"], &["d(?:4|a)rn"], &["darn it"])
386 /// .await?;
387 /// # Ok(()) }
388 /// ```
389 ///
390 /// [`MANAGE_GUILD`]: twilight_model::guild::Permissions::MANAGE_GUILD
391 pub const fn create_auto_moderation_rule<'a>(
392 &'a self,
393 guild_id: Id<GuildMarker>,
394 name: &'a str,
395 event_type: AutoModerationEventType,
396 ) -> CreateAutoModerationRule<'a> {
397 CreateAutoModerationRule::new(self, guild_id, name, event_type)
398 }
399
400 /// Delete an auto moderation rule in a guild.
401 ///
402 /// Requires the [`MANAGE_GUILD`] permission.
403 ///
404 /// [`MANAGE_GUILD`]: twilight_model::guild::Permissions::MANAGE_GUILD
405 pub const fn delete_auto_moderation_rule(
406 &self,
407 guild_id: Id<GuildMarker>,
408 auto_moderation_rule_id: Id<AutoModerationRuleMarker>,
409 ) -> DeleteAutoModerationRule<'_> {
410 DeleteAutoModerationRule::new(self, guild_id, auto_moderation_rule_id)
411 }
412
413 /// Update an auto moderation rule in a guild.
414 ///
415 /// Requires the [`MANAGE_GUILD`] permission.
416 ///
417 /// [`MANAGE_GUILD`]: twilight_model::guild::Permissions::MANAGE_GUILD
418 pub const fn update_auto_moderation_rule(
419 &self,
420 guild_id: Id<GuildMarker>,
421 auto_moderation_rule_id: Id<AutoModerationRuleMarker>,
422 ) -> UpdateAutoModerationRule<'_> {
423 UpdateAutoModerationRule::new(self, guild_id, auto_moderation_rule_id)
424 }
425
426 /// Get the audit log for a guild.
427 ///
428 /// # Examples
429 ///
430 /// ```no_run
431 /// # use twilight_http::Client;
432 /// use twilight_model::id::Id;
433 ///
434 /// # #[tokio::main]
435 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
436 /// # let client = Client::new("token".to_owned());
437 /// let guild_id = Id::new(101);
438 /// let audit_log = client.audit_log(guild_id).await?;
439 /// # Ok(()) }
440 /// ```
441 pub const fn audit_log(&self, guild_id: Id<GuildMarker>) -> GetAuditLog<'_> {
442 GetAuditLog::new(self, guild_id)
443 }
444
445 /// Retrieve the bans for a guild.
446 ///
447 /// # Examples
448 ///
449 /// Retrieve the bans for guild `1`:
450 ///
451 /// ```no_run
452 /// # use twilight_http::Client;
453 /// use twilight_model::id::Id;
454 /// #
455 /// # #[tokio::main]
456 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
457 /// # let client = Client::new("my token".to_owned());
458 /// #
459 /// let guild_id = Id::new(1);
460 ///
461 /// let bans = client.bans(guild_id).await?;
462 /// # Ok(()) }
463 /// ```
464 pub const fn bans(&self, guild_id: Id<GuildMarker>) -> GetBans<'_> {
465 GetBans::new(self, guild_id)
466 }
467
468 /// Get information about a ban of a guild.
469 ///
470 /// Includes the user banned and the reason.
471 pub const fn ban(&self, guild_id: Id<GuildMarker>, user_id: Id<UserMarker>) -> GetBan<'_> {
472 GetBan::new(self, guild_id, user_id)
473 }
474
475 /// Bans a user from a guild, optionally with the number of seconds' worth of
476 /// messages to delete and the reason.
477 ///
478 /// # Examples
479 ///
480 /// Ban user `200` from guild `100`, deleting
481 /// `86_400` second's (this is equivalent to `1` day) worth of messages, for the reason `"memes"`:
482 ///
483 /// ```no_run
484 /// # use twilight_http::{request::AuditLogReason, Client};
485 /// use twilight_model::id::Id;
486 /// #
487 /// # #[tokio::main]
488 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
489 /// # let client = Client::new("my token".to_owned());
490 /// #
491 /// let guild_id = Id::new(100);
492 /// let user_id = Id::new(200);
493 /// client
494 /// .create_ban(guild_id, user_id)
495 /// .delete_message_seconds(86_400)
496 /// .reason("memes")
497 /// .await?;
498 /// # Ok(()) }
499 /// ```
500 pub const fn create_ban(
501 &self,
502 guild_id: Id<GuildMarker>,
503 user_id: Id<UserMarker>,
504 ) -> CreateBan<'_> {
505 CreateBan::new(self, guild_id, user_id)
506 }
507
508 /// Remove a ban from a user in a guild.
509 ///
510 /// # Examples
511 ///
512 /// Unban user `200` from guild `100`:
513 ///
514 /// ```no_run
515 /// # use twilight_http::Client;
516 /// use twilight_model::id::Id;
517 /// #
518 /// # #[tokio::main]
519 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
520 /// # let client = Client::new("my token".to_owned());
521 /// #
522 /// let guild_id = Id::new(100);
523 /// let user_id = Id::new(200);
524 ///
525 /// client.delete_ban(guild_id, user_id).await?;
526 /// # Ok(()) }
527 /// ```
528 pub const fn delete_ban(
529 &self,
530 guild_id: Id<GuildMarker>,
531 user_id: Id<UserMarker>,
532 ) -> DeleteBan<'_> {
533 DeleteBan::new(self, guild_id, user_id)
534 }
535
536 /// Get a channel by its ID.
537 ///
538 /// # Examples
539 ///
540 /// Get channel `100`:
541 ///
542 /// ```no_run
543 /// # use twilight_http::Client;
544 /// # use twilight_model::id::Id;
545 /// #
546 /// # #[tokio::main]
547 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
548 /// # let client = Client::new("my token".to_owned());
549 /// #
550 /// let channel_id = Id::new(100);
551 /// #
552 /// let channel = client.channel(channel_id).await?;
553 /// # Ok(()) }
554 /// ```
555 pub const fn channel(&self, channel_id: Id<ChannelMarker>) -> GetChannel<'_> {
556 GetChannel::new(self, channel_id)
557 }
558
559 /// Delete a channel by ID.
560 pub const fn delete_channel(&self, channel_id: Id<ChannelMarker>) -> DeleteChannel<'_> {
561 DeleteChannel::new(self, channel_id)
562 }
563
564 /// Update a channel.
565 pub const fn update_channel(&self, channel_id: Id<ChannelMarker>) -> UpdateChannel<'_> {
566 UpdateChannel::new(self, channel_id)
567 }
568
569 /// Follows a news channel by [`Id<ChannelMarker>`].
570 ///
571 /// The type returned is [`FollowedChannel`].
572 ///
573 /// [`FollowedChannel`]: ::twilight_model::channel::FollowedChannel
574 pub const fn follow_news_channel(
575 &self,
576 channel_id: Id<ChannelMarker>,
577 webhook_channel_id: Id<ChannelMarker>,
578 ) -> FollowNewsChannel<'_> {
579 FollowNewsChannel::new(self, channel_id, webhook_channel_id)
580 }
581
582 /// Get the invites for a guild channel.
583 ///
584 /// Requires the [`MANAGE_CHANNELS`] permission. This method only works if
585 /// the channel is a guild channel.
586 ///
587 /// [`MANAGE_CHANNELS`]: twilight_model::guild::Permissions::MANAGE_CHANNELS
588 pub const fn channel_invites(&self, channel_id: Id<ChannelMarker>) -> GetChannelInvites<'_> {
589 GetChannelInvites::new(self, channel_id)
590 }
591
592 /// Get channel messages, by [`Id<ChannelMarker>`].
593 ///
594 /// Only one of [`after`], [`around`], and [`before`] can be specified at a time.
595 /// Once these are specified, the type returned is [`GetChannelMessagesConfigured`].
596 ///
597 /// If [`limit`] is unspecified, the default set by Discord is 50.
598 ///
599 /// # Examples
600 ///
601 /// ```no_run
602 /// use twilight_http::Client;
603 /// use twilight_model::id::Id;
604 ///
605 /// # #[tokio::main]
606 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
607 /// let client = Client::new("my token".to_owned());
608 /// let channel_id = Id::new(123);
609 /// let message_id = Id::new(234);
610 /// let limit: u16 = 6;
611 ///
612 /// let messages = client
613 /// .channel_messages(channel_id)
614 /// .before(message_id)
615 /// .limit(limit)
616 /// .await?;
617 ///
618 /// # Ok(()) }
619 /// ```
620 ///
621 /// # Errors
622 ///
623 /// Returns an error of type [`ValidationErrorType::GetChannelMessages`] if
624 /// the amount is less than 1 or greater than 100.
625 ///
626 /// [`GetChannelMessagesConfigured`]: crate::request::channel::message::GetChannelMessagesConfigured
627 /// [`ValidationErrorType::GetChannelMessages`]: twilight_validate::request::ValidationErrorType::GetChannelMessages
628 /// [`after`]: GetChannelMessages::after
629 /// [`around`]: GetChannelMessages::around
630 /// [`before`]: GetChannelMessages::before
631 /// [`limit`]: GetChannelMessages::limit
632 pub const fn channel_messages(&self, channel_id: Id<ChannelMarker>) -> GetChannelMessages<'_> {
633 GetChannelMessages::new(self, channel_id)
634 }
635
636 pub const fn delete_channel_permission(
637 &self,
638 channel_id: Id<ChannelMarker>,
639 ) -> DeleteChannelPermission<'_> {
640 DeleteChannelPermission::new(self, channel_id)
641 }
642
643 /// Update the permissions for a role or a user in a channel.
644 ///
645 /// # Examples:
646 ///
647 /// Create permission overrides for a role to view the channel, but not send
648 /// messages:
649 ///
650 /// ```no_run
651 /// # #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> {
652 /// # use twilight_http::Client;
653 /// # let client = Client::new("my token".to_owned());
654 /// #
655 /// use twilight_model::{
656 /// guild::Permissions,
657 /// http::permission_overwrite::{PermissionOverwrite, PermissionOverwriteType},
658 /// id::{marker::RoleMarker, Id},
659 /// };
660 ///
661 /// let channel_id = Id::new(123);
662 /// let role_id: Id<RoleMarker> = Id::new(432);
663 /// let permission_overwrite = PermissionOverwrite {
664 /// allow: Some(Permissions::VIEW_CHANNEL),
665 /// deny: Some(Permissions::SEND_MESSAGES),
666 /// id: role_id.cast(),
667 /// kind: PermissionOverwriteType::Role,
668 /// };
669 ///
670 /// client
671 /// .update_channel_permission(channel_id, &permission_overwrite)
672 /// .await?;
673 /// # Ok(()) }
674 /// ```
675 pub const fn update_channel_permission(
676 &self,
677 channel_id: Id<ChannelMarker>,
678 permission_overwrite: &PermissionOverwrite,
679 ) -> UpdateChannelPermission<'_> {
680 UpdateChannelPermission::new(self, channel_id, permission_overwrite)
681 }
682
683 /// Get all the webhooks of a channel.
684 pub const fn channel_webhooks(&self, channel_id: Id<ChannelMarker>) -> GetChannelWebhooks<'_> {
685 GetChannelWebhooks::new(self, channel_id)
686 }
687
688 /// Get information about the current user.
689 pub const fn current_user(&self) -> GetCurrentUser<'_> {
690 GetCurrentUser::new(self)
691 }
692
693 /// Get information about the current user in a guild.
694 pub const fn current_user_guild_member(
695 &self,
696 guild_id: Id<GuildMarker>,
697 ) -> GetCurrentUserGuildMember<'_> {
698 GetCurrentUserGuildMember::new(self, guild_id)
699 }
700
701 /// Get information about the current OAuth2 authorization.
702 pub const fn current_authorization(&self) -> GetCurrentAuthorizationInformation<'_> {
703 GetCurrentAuthorizationInformation::new(self)
704 }
705
706 /// Get information about the current bot application.
707 pub const fn current_user_application(&self) -> GetUserApplicationInfo<'_> {
708 GetUserApplicationInfo::new(self)
709 }
710
711 /// Update the current user's application.
712 pub const fn update_current_user_application(&self) -> UpdateCurrentUserApplication<'_> {
713 UpdateCurrentUserApplication::new(self)
714 }
715
716 /// Update the current user.
717 ///
718 /// All parameters are optional. If the username is changed, it may cause the discriminator to
719 /// be randomized.
720 pub const fn update_current_user(&self) -> UpdateCurrentUser<'_> {
721 UpdateCurrentUser::new(self)
722 }
723
724 /// Get voice state of the current user in a guild.
725 ///
726 /// # Caveats
727 ///
728 /// - Current user must already have joined a voice/stage channel in this guild.
729 pub const fn current_user_voice_state(
730 &self,
731 guild_id: Id<GuildMarker>,
732 ) -> GetCurrentUserVoiceState<'_> {
733 GetCurrentUserVoiceState::new(self, guild_id)
734 }
735
736 /// Update the current user's voice state.
737 ///
738 /// All parameters are optional.
739 ///
740 /// # Caveats
741 ///
742 /// - `channel_id` must currently point to a stage channel.
743 /// - Current user must have already joined `channel_id`.
744 pub const fn update_current_user_voice_state(
745 &self,
746 guild_id: Id<GuildMarker>,
747 ) -> UpdateCurrentUserVoiceState<'_> {
748 UpdateCurrentUserVoiceState::new(self, guild_id)
749 }
750
751 /// Get the current user's connections.
752 ///
753 /// Requires the `connections` `OAuth2` scope.
754 pub const fn current_user_connections(&self) -> GetCurrentUserConnections<'_> {
755 GetCurrentUserConnections::new(self)
756 }
757
758 /// Returns a list of guilds for the current user.
759 ///
760 /// # Examples
761 ///
762 /// Get the first 25 guilds with an ID after `300` and before
763 /// `400`:
764 ///
765 /// ```no_run
766 /// # use twilight_http::Client;
767 /// use twilight_model::id::Id;
768 ///
769 /// # #[tokio::main]
770 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
771 /// # let client = Client::new("my token".to_owned());
772 /// #
773 /// let after = Id::new(300);
774 /// let before = Id::new(400);
775 /// let guilds = client
776 /// .current_user_guilds()
777 /// .after(after)
778 /// .before(before)
779 /// .limit(25)
780 /// .await?;
781 /// # Ok(()) }
782 /// ```
783 pub const fn current_user_guilds(&self) -> GetCurrentUserGuilds<'_> {
784 GetCurrentUserGuilds::new(self)
785 }
786
787 /// Get the emojis for a guild, by the guild's id.
788 ///
789 /// # Examples
790 ///
791 /// Get the emojis for guild `100`:
792 ///
793 /// ```no_run
794 /// # use twilight_http::Client;
795 /// # use twilight_model::id::Id;
796 /// #
797 /// # #[tokio::main]
798 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
799 /// # let client = Client::new("my token".to_owned());
800 /// #
801 /// let guild_id = Id::new(100);
802 ///
803 /// client.emojis(guild_id).await?;
804 /// # Ok(()) }
805 /// ```
806 pub const fn emojis(&self, guild_id: Id<GuildMarker>) -> GetEmojis<'_> {
807 GetEmojis::new(self, guild_id)
808 }
809
810 /// Get the entitlements for an application.
811 ///
812 /// # Examples
813 ///
814 /// Get emojis for the application `100`:
815 ///
816 /// ```no_run
817 /// # use twilight_http::Client;
818 /// # use twilight_model::id::Id;
819 ///
820 /// # #[tokio::main]
821 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
822 /// # let client = Client::new("my token".to_owned());
823 /// #
824 /// let application_id = Id::new(100);
825 ///
826 /// client.entitlements(application_id).await?;
827 /// # Ok(()) }
828 /// ```
829 pub const fn entitlements(&self, application_id: Id<ApplicationMarker>) -> GetEntitlements<'_> {
830 GetEntitlements::new(self, application_id)
831 }
832
833 /// Get an emoji for a guild by the the guild's ID and emoji's ID.
834 ///
835 /// # Examples
836 ///
837 /// Get emoji `100` from guild `50`:
838 ///
839 /// ```no_run
840 /// # use twilight_http::Client;
841 /// # use twilight_model::id::Id;
842 /// #
843 /// # #[tokio::main]
844 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
845 /// # let client = Client::new("my token".to_owned());
846 /// #
847 /// let guild_id = Id::new(50);
848 /// let emoji_id = Id::new(100);
849 ///
850 /// client.emoji(guild_id, emoji_id).await?;
851 /// # Ok(()) }
852 /// ```
853 pub const fn emoji(
854 &self,
855 guild_id: Id<GuildMarker>,
856 emoji_id: Id<EmojiMarker>,
857 ) -> GetEmoji<'_> {
858 GetEmoji::new(self, guild_id, emoji_id)
859 }
860
861 /// Create an emoji in a guild.
862 ///
863 /// The emoji must be a Data URI, in the form of
864 /// `data:image/{type};base64,{data}` where `{type}` is the image MIME type
865 /// and `{data}` is the base64-encoded image. See [Discord Docs/Image Data].
866 ///
867 /// [Discord Docs/Image Data]: https://discord.com/developers/docs/reference#image-data
868 pub const fn create_emoji<'a>(
869 &'a self,
870 guild_id: Id<GuildMarker>,
871 name: &'a str,
872 image: &'a str,
873 ) -> CreateEmoji<'a> {
874 CreateEmoji::new(self, guild_id, name, image)
875 }
876
877 /// Delete an emoji in a guild, by id.
878 pub const fn delete_emoji(
879 &self,
880 guild_id: Id<GuildMarker>,
881 emoji_id: Id<EmojiMarker>,
882 ) -> DeleteEmoji<'_> {
883 DeleteEmoji::new(self, guild_id, emoji_id)
884 }
885
886 /// Update an emoji in a guild, by id.
887 pub const fn update_emoji(
888 &self,
889 guild_id: Id<GuildMarker>,
890 emoji_id: Id<EmojiMarker>,
891 ) -> UpdateEmoji<'_> {
892 UpdateEmoji::new(self, guild_id, emoji_id)
893 }
894
895 /// Get information about the gateway, optionally with additional information detailing the
896 /// number of shards to use and sessions remaining.
897 ///
898 /// # Examples
899 ///
900 /// Get the gateway connection URL without bot information:
901 ///
902 /// ```no_run
903 /// # use twilight_http::Client;
904 /// #
905 /// # #[tokio::main]
906 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
907 /// # let client = Client::new("my token".to_owned());
908 /// #
909 /// let info = client.gateway().await?;
910 /// # Ok(()) }
911 /// ```
912 ///
913 /// Get the gateway connection URL with additional shard and session information, which
914 /// requires specifying a bot token:
915 ///
916 /// ```no_run
917 /// # use twilight_http::Client;
918 /// #
919 /// # #[tokio::main]
920 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
921 /// # let client = Client::new("my token".to_owned());
922 /// #
923 /// let info = client.gateway().authed().await?.model().await?;
924 ///
925 /// println!("URL: {}", info.url);
926 /// println!("Recommended shards to use: {}", info.shards);
927 /// # Ok(()) }
928 /// ```
929 pub const fn gateway(&self) -> GetGateway<'_> {
930 GetGateway::new(self)
931 }
932
933 /// Get information about a guild.
934 pub const fn guild(&self, guild_id: Id<GuildMarker>) -> GetGuild<'_> {
935 GetGuild::new(self, guild_id)
936 }
937
938 /// Create a new request to create a guild.
939 ///
940 /// The minimum length of the name is 2 UTF-16 characters and the maximum is 100 UTF-16
941 /// characters. This endpoint can only be used by bots in less than 10 guilds.
942 ///
943 /// # Errors
944 ///
945 /// Returns a [`CreateGuildErrorType::NameInvalid`] error type if the name
946 /// length is too short or too long.
947 ///
948 /// [`CreateGuildErrorType::NameInvalid`]: crate::request::guild::create_guild::CreateGuildErrorType::NameInvalid
949 pub fn create_guild(&self, name: String) -> CreateGuild<'_> {
950 CreateGuild::new(self, name)
951 }
952
953 /// Delete a guild permanently. The user must be the owner.
954 pub const fn delete_guild(&self, guild_id: Id<GuildMarker>) -> DeleteGuild<'_> {
955 DeleteGuild::new(self, guild_id)
956 }
957
958 /// Update a guild.
959 ///
960 /// All endpoints are optional. See [Discord Docs/Modify Guild].
961 ///
962 /// [Discord Docs/Modify Guild]: https://discord.com/developers/docs/resources/guild#modify-guild
963 pub const fn update_guild(&self, guild_id: Id<GuildMarker>) -> UpdateGuild<'_> {
964 UpdateGuild::new(self, guild_id)
965 }
966
967 /// Leave a guild by id.
968 pub const fn leave_guild(&self, guild_id: Id<GuildMarker>) -> LeaveGuild<'_> {
969 LeaveGuild::new(self, guild_id)
970 }
971
972 /// Get the channels in a guild.
973 pub const fn guild_channels(&self, guild_id: Id<GuildMarker>) -> GetGuildChannels<'_> {
974 GetGuildChannels::new(self, guild_id)
975 }
976
977 /// Create a new request to create a guild channel.
978 ///
979 /// All fields are optional except for name. The minimum length of the name
980 /// is 1 UTF-16 character and the maximum is 100 UTF-16 characters.
981 ///
982 /// # Errors
983 ///
984 /// Returns an error of type [`NameInvalid`] when the length of the name is
985 /// either fewer than 1 UTF-16 character or more than 100 UTF-16 characters.
986 ///
987 /// Returns an error of type [`RateLimitPerUserInvalid`] when the seconds of
988 /// the rate limit per user is more than 21600.
989 ///
990 /// Returns an error of type [`TopicInvalid`] when the length of the topic
991 /// is more than 1024 UTF-16 characters.
992 ///
993 /// [`NameInvalid`]: twilight_validate::channel::ChannelValidationErrorType::NameInvalid
994 /// [`RateLimitPerUserInvalid`]: twilight_validate::channel::ChannelValidationErrorType::RateLimitPerUserInvalid
995 /// [`TopicInvalid`]: twilight_validate::channel::ChannelValidationErrorType::TopicInvalid
996 pub fn create_guild_channel<'a>(
997 &'a self,
998 guild_id: Id<GuildMarker>,
999 name: &'a str,
1000 ) -> CreateGuildChannel<'a> {
1001 CreateGuildChannel::new(self, guild_id, name)
1002 }
1003
1004 /// Modify the guild onboarding flow.
1005 pub const fn update_guild_onboarding(
1006 &self,
1007 guild_id: Id<GuildMarker>,
1008 fields: UpdateGuildOnboardingFields,
1009 ) -> UpdateGuildOnboarding {
1010 UpdateGuildOnboarding::new(self, guild_id, fields)
1011 }
1012
1013 /// Modify the positions of the channels.
1014 ///
1015 /// The minimum amount of channels to modify, is a swap between two channels.
1016 pub const fn update_guild_channel_positions<'a>(
1017 &'a self,
1018 guild_id: Id<GuildMarker>,
1019 channel_positions: &'a [Position],
1020 ) -> UpdateGuildChannelPositions<'a> {
1021 UpdateGuildChannelPositions::new(self, guild_id, channel_positions)
1022 }
1023
1024 /// Get a guild's widget.
1025 ///
1026 /// See [Discord Docs/Get Guild Widget].
1027 ///
1028 /// [Discord Docs/Get Guild Widget]: https://discord.com/developers/docs/resources/guild#get-guild-widget
1029 pub const fn guild_widget(&self, guild_id: Id<GuildMarker>) -> GetGuildWidget<'_> {
1030 GetGuildWidget::new(self, guild_id)
1031 }
1032
1033 /// Get a guild's widget settings.
1034 ///
1035 /// See [Discord Docs/Get Guild Widget Settings].
1036 ///
1037 /// [Discord Docs/Get Guild Widget]: https://discord.com/developers/docs/resources/guild#get-guild-widget-settings
1038 pub const fn guild_widget_settings(
1039 &self,
1040 guild_id: Id<GuildMarker>,
1041 ) -> GetGuildWidgetSettings<'_> {
1042 GetGuildWidgetSettings::new(self, guild_id)
1043 }
1044
1045 /// Modify a guild's widget.
1046 ///
1047 /// See [Discord Docs/Modify Guild Widget].
1048 ///
1049 /// [Discord Docs/Modify Guild Widget]: https://discord.com/developers/docs/resources/guild#modify-guild-widget
1050 pub const fn update_guild_widget_settings(
1051 &self,
1052 guild_id: Id<GuildMarker>,
1053 ) -> UpdateGuildWidgetSettings<'_> {
1054 UpdateGuildWidgetSettings::new(self, guild_id)
1055 }
1056
1057 /// Get the guild's integrations.
1058 pub const fn guild_integrations(&self, guild_id: Id<GuildMarker>) -> GetGuildIntegrations<'_> {
1059 GetGuildIntegrations::new(self, guild_id)
1060 }
1061
1062 /// Delete an integration for a guild, by the integration's id.
1063 pub const fn delete_guild_integration(
1064 &self,
1065 guild_id: Id<GuildMarker>,
1066 integration_id: Id<IntegrationMarker>,
1067 ) -> DeleteGuildIntegration<'_> {
1068 DeleteGuildIntegration::new(self, guild_id, integration_id)
1069 }
1070
1071 /// Get information about the invites of a guild.
1072 ///
1073 /// Requires the [`MANAGE_GUILD`] permission.
1074 ///
1075 /// [`MANAGE_GUILD`]: twilight_model::guild::Permissions::MANAGE_GUILD
1076 pub const fn guild_invites(&self, guild_id: Id<GuildMarker>) -> GetGuildInvites<'_> {
1077 GetGuildInvites::new(self, guild_id)
1078 }
1079
1080 /// Update a guild's MFA level.
1081 pub const fn update_guild_mfa(
1082 &self,
1083 guild_id: Id<GuildMarker>,
1084 level: MfaLevel,
1085 ) -> UpdateGuildMfa<'_> {
1086 UpdateGuildMfa::new(self, guild_id, level)
1087 }
1088
1089 /// Get the members of a guild, by id.
1090 ///
1091 /// The upper limit to this request is 1000. If more than 1000 members are needed, the requests
1092 /// must be chained. Discord defaults the limit to 1.
1093 ///
1094 /// # Examples
1095 ///
1096 /// Get the first 500 members of guild `100` after user ID `3000`:
1097 ///
1098 /// ```no_run
1099 /// # use twilight_http::Client;
1100 /// use twilight_model::id::Id;
1101 /// #
1102 /// # #[tokio::main]
1103 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
1104 /// # let client = Client::new("my token".to_owned());
1105 /// #
1106 /// let guild_id = Id::new(100);
1107 /// let user_id = Id::new(3000);
1108 /// let members = client
1109 /// .guild_members(guild_id)
1110 /// .after(user_id)
1111 /// .limit(500)
1112 /// .await?;
1113 /// # Ok(()) }
1114 /// ```
1115 ///
1116 /// # Errors
1117 ///
1118 /// Returns an error of type [`ValidationErrorType::GetGuildMembers`] if the
1119 /// limit is invalid.
1120 ///
1121 /// [`ValidationErrorType::GetGuildMembers`]: twilight_validate::request::ValidationErrorType::GetGuildMembers
1122 pub const fn guild_members(&self, guild_id: Id<GuildMarker>) -> GetGuildMembers<'_> {
1123 GetGuildMembers::new(self, guild_id)
1124 }
1125
1126 /// Search the members of a specific guild by a query.
1127 ///
1128 /// The upper limit to this request is 1000. Discord defaults the limit to 1.
1129 ///
1130 /// # Examples
1131 ///
1132 /// Get the first 10 members of guild `100` matching `Wumpus`:
1133 ///
1134 /// ```no_run
1135 /// use twilight_http::Client;
1136 /// use twilight_model::id::Id;
1137 ///
1138 /// # #[tokio::main]
1139 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
1140 /// let client = Client::new("my token".to_owned());
1141 ///
1142 /// let guild_id = Id::new(100);
1143 /// let members = client
1144 /// .search_guild_members(guild_id, "Wumpus")
1145 /// .limit(10)
1146 /// .await?;
1147 /// # Ok(()) }
1148 /// ```
1149 ///
1150 /// # Errors
1151 ///
1152 /// Returns an error of type [`ValidationErrorType::SearchGuildMembers`] if
1153 /// the limit is invalid.
1154 ///
1155 /// [`GUILD_MEMBERS`]: twilight_model::gateway::Intents::GUILD_MEMBERS
1156 /// [`ValidationErrorType::SearchGuildMembers`]: twilight_validate::request::ValidationErrorType::SearchGuildMembers
1157 pub const fn search_guild_members<'a>(
1158 &'a self,
1159 guild_id: Id<GuildMarker>,
1160 query: &'a str,
1161 ) -> SearchGuildMembers<'a> {
1162 SearchGuildMembers::new(self, guild_id, query)
1163 }
1164
1165 /// Get a member of a guild, by their id.
1166 pub const fn guild_member(
1167 &self,
1168 guild_id: Id<GuildMarker>,
1169 user_id: Id<UserMarker>,
1170 ) -> GetMember<'_> {
1171 GetMember::new(self, guild_id, user_id)
1172 }
1173
1174 /// Add a user to a guild.
1175 ///
1176 /// An access token for the user with `guilds.join` scope is required. All
1177 /// other fields are optional. See [Discord Docs/Add Guild Member].
1178 ///
1179 /// # Errors
1180 ///
1181 /// Returns an error of type [`ValidationErrorType::Nickname`] if the
1182 /// nickname is too short or too long.
1183 ///
1184 /// [`ValidationErrorType::Nickname`]: twilight_validate::request::ValidationErrorType::Nickname
1185 /// [Discord Docs/Add Guild Member]: https://discord.com/developers/docs/resources/guild#add-guild-member
1186 pub const fn add_guild_member<'a>(
1187 &'a self,
1188 guild_id: Id<GuildMarker>,
1189 user_id: Id<UserMarker>,
1190 access_token: &'a str,
1191 ) -> AddGuildMember<'a> {
1192 AddGuildMember::new(self, guild_id, user_id, access_token)
1193 }
1194
1195 /// Kick a member from a guild.
1196 pub const fn remove_guild_member(
1197 &self,
1198 guild_id: Id<GuildMarker>,
1199 user_id: Id<UserMarker>,
1200 ) -> RemoveMember<'_> {
1201 RemoveMember::new(self, guild_id, user_id)
1202 }
1203
1204 /// Update a guild member.
1205 ///
1206 /// All fields are optional. See [Discord Docs/Modify Guild Member].
1207 ///
1208 /// # Examples
1209 ///
1210 /// Update a member's nickname to "pinky pie" and server mute them:
1211 ///
1212 /// ```no_run
1213 /// use std::env;
1214 /// use twilight_http::Client;
1215 /// use twilight_model::id::Id;
1216 ///
1217 /// # #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> {
1218 /// let client = Client::new(env::var("DISCORD_TOKEN")?);
1219 /// let member = client
1220 /// .update_guild_member(Id::new(1), Id::new(2))
1221 /// .mute(true)
1222 /// .nick(Some("pinkie pie"))
1223 /// .await?
1224 /// .model()
1225 /// .await?;
1226 ///
1227 /// println!(
1228 /// "user {} now has the nickname '{:?}'",
1229 /// member.user.id, member.nick,
1230 /// );
1231 /// # Ok(()) }
1232 /// ```
1233 ///
1234 /// # Errors
1235 ///
1236 /// Returns an error of type [`ValidationErrorType::Nickname`] if the
1237 /// nickname length is too short or too long.
1238 ///
1239 /// [`ValidationErrorType::Nickname`]: twilight_validate::request::ValidationErrorType::Nickname
1240 /// [Discord Docs/Modify Guild Member]: https://discord.com/developers/docs/resources/guild#modify-guild-member
1241 pub const fn update_guild_member(
1242 &self,
1243 guild_id: Id<GuildMarker>,
1244 user_id: Id<UserMarker>,
1245 ) -> UpdateGuildMember<'_> {
1246 UpdateGuildMember::new(self, guild_id, user_id)
1247 }
1248
1249 /// Update the user's member in a guild.
1250 pub const fn update_current_member(
1251 &self,
1252 guild_id: Id<GuildMarker>,
1253 ) -> UpdateCurrentMember<'_> {
1254 UpdateCurrentMember::new(self, guild_id)
1255 }
1256
1257 /// Add a role to a member in a guild.
1258 ///
1259 /// # Examples
1260 ///
1261 /// In guild `1`, add role `2` to user `3`, for the reason `"test"`:
1262 ///
1263 /// ```no_run
1264 /// # use twilight_http::{request::AuditLogReason, Client};
1265 /// use twilight_model::id::Id;
1266 /// #
1267 /// # #[tokio::main]
1268 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
1269 /// # let client = Client::new("my token".to_owned());
1270 /// #
1271 /// let guild_id = Id::new(1);
1272 /// let role_id = Id::new(2);
1273 /// let user_id = Id::new(3);
1274 ///
1275 /// client
1276 /// .add_guild_member_role(guild_id, user_id, role_id)
1277 /// .reason("test")
1278 /// .await?;
1279 /// # Ok(()) }
1280 /// ```
1281 pub const fn add_guild_member_role(
1282 &self,
1283 guild_id: Id<GuildMarker>,
1284 user_id: Id<UserMarker>,
1285 role_id: Id<RoleMarker>,
1286 ) -> AddRoleToMember<'_> {
1287 AddRoleToMember::new(self, guild_id, user_id, role_id)
1288 }
1289
1290 /// Remove a role from a member in a guild, by id.
1291 pub const fn remove_guild_member_role(
1292 &self,
1293 guild_id: Id<GuildMarker>,
1294 user_id: Id<UserMarker>,
1295 role_id: Id<RoleMarker>,
1296 ) -> RemoveRoleFromMember<'_> {
1297 RemoveRoleFromMember::new(self, guild_id, user_id, role_id)
1298 }
1299
1300 /// Retrieves the onboarding data for a guild.
1301 pub const fn guild_onboarding(&self, guild_id: Id<GuildMarker>) -> GetGuildOnboarding<'_> {
1302 GetGuildOnboarding::new(self, guild_id)
1303 }
1304
1305 /// For public guilds, get the guild preview.
1306 ///
1307 /// This works even if the user is not in the guild.
1308 pub const fn guild_preview(&self, guild_id: Id<GuildMarker>) -> GetGuildPreview<'_> {
1309 GetGuildPreview::new(self, guild_id)
1310 }
1311
1312 /// Get the counts of guild members to be pruned.
1313 pub const fn guild_prune_count(&self, guild_id: Id<GuildMarker>) -> GetGuildPruneCount<'_> {
1314 GetGuildPruneCount::new(self, guild_id)
1315 }
1316
1317 /// Begin a guild prune.
1318 ///
1319 /// See [Discord Docs/Begin Guild Prune].
1320 ///
1321 /// [Discord Docs/Begin Guild Prune]: https://discord.com/developers/docs/resources/guild#begin-guild-prune
1322 pub const fn create_guild_prune(&self, guild_id: Id<GuildMarker>) -> CreateGuildPrune<'_> {
1323 CreateGuildPrune::new(self, guild_id)
1324 }
1325
1326 /// Get a guild's vanity url, if there is one.
1327 pub const fn guild_vanity_url(&self, guild_id: Id<GuildMarker>) -> GetGuildVanityUrl<'_> {
1328 GetGuildVanityUrl::new(self, guild_id)
1329 }
1330
1331 /// Get voice region data for the guild.
1332 ///
1333 /// Can return VIP servers if the guild is VIP-enabled.
1334 pub const fn guild_voice_regions(&self, guild_id: Id<GuildMarker>) -> GetGuildVoiceRegions<'_> {
1335 GetGuildVoiceRegions::new(self, guild_id)
1336 }
1337
1338 /// Get the webhooks of a guild.
1339 pub const fn guild_webhooks(&self, guild_id: Id<GuildMarker>) -> GetGuildWebhooks<'_> {
1340 GetGuildWebhooks::new(self, guild_id)
1341 }
1342
1343 /// Get the guild's welcome screen.
1344 ///
1345 /// If the welcome screen is not enabled, this requires the [`MANAGE_GUILD`]
1346 /// permission.
1347 ///
1348 /// [`MANAGE_GUILD`]: twilight_model::guild::Permissions::MANAGE_GUILD
1349 pub const fn guild_welcome_screen(
1350 &self,
1351 guild_id: Id<GuildMarker>,
1352 ) -> GetGuildWelcomeScreen<'_> {
1353 GetGuildWelcomeScreen::new(self, guild_id)
1354 }
1355
1356 /// Update the guild's welcome screen.
1357 ///
1358 /// Requires the [`MANAGE_GUILD`] permission.
1359 ///
1360 /// [`MANAGE_GUILD`]: twilight_model::guild::Permissions::MANAGE_GUILD
1361 pub const fn update_guild_welcome_screen(
1362 &self,
1363 guild_id: Id<GuildMarker>,
1364 ) -> UpdateGuildWelcomeScreen<'_> {
1365 UpdateGuildWelcomeScreen::new(self, guild_id)
1366 }
1367
1368 /// Get information about an invite by its code.
1369 ///
1370 /// If [`with_counts`] is called, the returned invite will contain
1371 /// approximate member counts. If [`with_expiration`] is called, it will
1372 /// contain the expiration date.
1373 ///
1374 /// # Examples
1375 ///
1376 /// ```no_run
1377 /// # use twilight_http::Client;
1378 /// #
1379 /// # #[tokio::main]
1380 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
1381 /// # let client = Client::new("my token".to_owned());
1382 /// #
1383 /// let invite = client.invite("code").with_counts().await?;
1384 /// # Ok(()) }
1385 /// ```
1386 ///
1387 /// [`with_counts`]: crate::request::channel::invite::GetInvite::with_counts
1388 /// [`with_expiration`]: crate::request::channel::invite::GetInvite::with_expiration
1389 pub const fn invite<'a>(&'a self, code: &'a str) -> GetInvite<'a> {
1390 GetInvite::new(self, code)
1391 }
1392
1393 /// Create an invite, with options.
1394 ///
1395 /// Requires the [`CREATE_INVITE`] permission.
1396 ///
1397 /// # Examples
1398 ///
1399 /// ```no_run
1400 /// # use twilight_http::Client;
1401 /// # use twilight_model::id::Id;
1402 /// #
1403 /// # #[tokio::main]
1404 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
1405 /// # let client = Client::new("my token".to_owned());
1406 /// #
1407 /// let channel_id = Id::new(123);
1408 /// let invite = client.create_invite(channel_id).max_uses(3).await?;
1409 /// # Ok(()) }
1410 /// ```
1411 ///
1412 /// [`CREATE_INVITE`]: twilight_model::guild::Permissions::CREATE_INVITE
1413 pub const fn create_invite(&self, channel_id: Id<ChannelMarker>) -> CreateInvite<'_> {
1414 CreateInvite::new(self, channel_id)
1415 }
1416
1417 /// Delete an invite by its code.
1418 ///
1419 /// Requires the [`MANAGE_CHANNELS`] permission on the channel this invite
1420 /// belongs to, or [`MANAGE_GUILD`] to remove any invite across the guild.
1421 ///
1422 /// [`MANAGE_CHANNELS`]: twilight_model::guild::Permissions::MANAGE_CHANNELS
1423 /// [`MANAGE_GUILD`]: twilight_model::guild::Permissions::MANAGE_GUILD
1424 pub const fn delete_invite<'a>(&'a self, code: &'a str) -> DeleteInvite<'a> {
1425 DeleteInvite::new(self, code)
1426 }
1427
1428 /// Get a message by [`Id<ChannelMarker>`] and [`Id<MessageMarker>`].
1429 pub const fn message(
1430 &self,
1431 channel_id: Id<ChannelMarker>,
1432 message_id: Id<MessageMarker>,
1433 ) -> GetMessage<'_> {
1434 GetMessage::new(self, channel_id, message_id)
1435 }
1436
1437 /// Send a message to a channel.
1438 ///
1439 /// The message must include at least one of [`attachments`],
1440 /// [`components`], [`content`], [`embeds`], or [`sticker_ids`].
1441 ///
1442 /// # Example
1443 ///
1444 /// ```no_run
1445 /// # #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> {
1446 /// use twilight_http::Client;
1447 /// use twilight_model::id::Id;
1448 ///
1449 /// let client = Client::new("my token".to_owned());
1450 ///
1451 /// let channel_id = Id::new(123);
1452 /// let message = client
1453 /// .create_message(channel_id)
1454 /// .content("Twilight is best pony")
1455 /// .tts(true)
1456 /// .await?;
1457 /// # Ok(()) }
1458 /// ```
1459 ///
1460 /// [`attachments`]: CreateMessage::attachments
1461 /// [`components`]: CreateMessage::components
1462 /// [`content`]: CreateMessage::content
1463 /// [`embeds`]: CreateMessage::embeds
1464 /// [`sticker_ids`]: CreateMessage::sticker_ids
1465 pub const fn create_message(&self, channel_id: Id<ChannelMarker>) -> CreateMessage<'_> {
1466 CreateMessage::new(self, channel_id)
1467 }
1468
1469 /// Delete a message by [`Id<ChannelMarker>`] and [`Id<MessageMarker>`].
1470 pub const fn delete_message(
1471 &self,
1472 channel_id: Id<ChannelMarker>,
1473 message_id: Id<MessageMarker>,
1474 ) -> DeleteMessage<'_> {
1475 DeleteMessage::new(self, channel_id, message_id)
1476 }
1477
1478 /// Delete messages by [`Id<ChannelMarker>`] and Vec<[`Id<MessageMarker>`]>.
1479 ///
1480 /// The vec count can be between 2 and 100. If the supplied
1481 /// [`Id<MessageMarker>`]s are invalid, they still count towards the lower
1482 /// and upper limits. This method will not delete messages older than two
1483 /// weeks. See [Discord Docs/Bulk Delete Messages].
1484 ///
1485 /// # Errors
1486 ///
1487 /// Returns an error of type
1488 /// [`ChannelValidationErrorType::BulkDeleteMessagesInvalid`] when the number of
1489 /// messages to delete in bulk is invalid.
1490 ///
1491 /// [Discord Docs/Bulk Delete Messages]: https://discord.com/developers/docs/resources/channel#bulk-delete-messages
1492 /// [`ChannelValidationErrorType::BulkDeleteMessagesInvalid`]: twilight_validate::channel::ChannelValidationErrorType::BulkDeleteMessagesInvalid
1493 pub fn delete_messages<'a>(
1494 &'a self,
1495 channel_id: Id<ChannelMarker>,
1496 message_ids: &'a [Id<MessageMarker>],
1497 ) -> DeleteMessages<'a> {
1498 DeleteMessages::new(self, channel_id, message_ids)
1499 }
1500
1501 /// Update a message by [`Id<ChannelMarker>`] and [`Id<MessageMarker>`].
1502 ///
1503 /// You can pass [`None`] to any of the methods to remove the associated
1504 /// field. Pass [`None`] to [`content`] to remove the content. You must
1505 /// ensure that the message still contains at least one of [`attachments`],
1506 /// [`components`], [`content`], [`embeds`], or stickers.
1507 ///
1508 /// # Examples
1509 ///
1510 /// Replace the content with `"test update"`:
1511 ///
1512 /// ```no_run
1513 /// # #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> {
1514 /// use twilight_http::Client;
1515 /// use twilight_model::id::Id;
1516 ///
1517 /// let client = Client::new("my token".to_owned());
1518 /// client
1519 /// .update_message(Id::new(1), Id::new(2))
1520 /// .content(Some("test update"))
1521 /// .await?;
1522 /// # Ok(()) }
1523 /// ```
1524 ///
1525 /// Remove the message's content:
1526 ///
1527 /// ```no_run
1528 /// # use twilight_http::Client;
1529 /// # use twilight_model::id::Id;
1530 /// #
1531 /// # #[tokio::main]
1532 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
1533 /// # let client = Client::new("my token".to_owned());
1534 /// client
1535 /// .update_message(Id::new(1), Id::new(2))
1536 /// .content(None)
1537 /// .await?;
1538 /// # Ok(()) }
1539 /// ```
1540 ///
1541 /// [`attachments`]: UpdateMessage::attachments
1542 /// [`components`]: UpdateMessage::components
1543 /// [`content`]: UpdateMessage::content
1544 /// [`embeds`]: UpdateMessage::embeds
1545 pub const fn update_message(
1546 &self,
1547 channel_id: Id<ChannelMarker>,
1548 message_id: Id<MessageMarker>,
1549 ) -> UpdateMessage<'_> {
1550 UpdateMessage::new(self, channel_id, message_id)
1551 }
1552
1553 /// Crosspost a message by [`Id<ChannelMarker>`] and [`Id<MessageMarker>`].
1554 pub const fn crosspost_message(
1555 &self,
1556 channel_id: Id<ChannelMarker>,
1557 message_id: Id<MessageMarker>,
1558 ) -> CrosspostMessage<'_> {
1559 CrosspostMessage::new(self, channel_id, message_id)
1560 }
1561
1562 /// Get the pins of a channel.
1563 pub const fn pins(&self, channel_id: Id<ChannelMarker>) -> GetPins<'_> {
1564 GetPins::new(self, channel_id)
1565 }
1566
1567 /// Create a new pin in a channel, by ID.
1568 pub const fn create_pin(
1569 &self,
1570 channel_id: Id<ChannelMarker>,
1571 message_id: Id<MessageMarker>,
1572 ) -> CreatePin<'_> {
1573 CreatePin::new(self, channel_id, message_id)
1574 }
1575
1576 /// Delete a pin in a channel, by ID.
1577 pub const fn delete_pin(
1578 &self,
1579 channel_id: Id<ChannelMarker>,
1580 message_id: Id<MessageMarker>,
1581 ) -> DeletePin<'_> {
1582 DeletePin::new(self, channel_id, message_id)
1583 }
1584
1585 /// Get a list of users that reacted to a message with an `emoji`.
1586 ///
1587 /// This endpoint is limited to 100 users maximum, so if a message has more than 100 reactions,
1588 /// requests must be chained until all reactions are retrieved.
1589 pub const fn reactions<'a>(
1590 &'a self,
1591 channel_id: Id<ChannelMarker>,
1592 message_id: Id<MessageMarker>,
1593 emoji: &'a RequestReactionType<'a>,
1594 ) -> GetReactions<'a> {
1595 GetReactions::new(self, channel_id, message_id, emoji)
1596 }
1597
1598 /// Create a reaction in a [`Id<ChannelMarker>`] on a [`Id<MessageMarker>`].
1599 ///
1600 /// The reaction must be a variant of [`RequestReactionType`].
1601 ///
1602 /// # Examples
1603 /// ```no_run
1604 /// # use twilight_http::{Client, request::channel::reaction::RequestReactionType};
1605 /// # use twilight_model::id::Id;
1606 /// #
1607 /// # #[tokio::main]
1608 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
1609 /// # let client = Client::new("my token".to_owned());
1610 /// #
1611 /// let channel_id = Id::new(123);
1612 /// let message_id = Id::new(456);
1613 /// let emoji = RequestReactionType::Unicode { name: "🌃" };
1614 ///
1615 /// let reaction = client
1616 /// .create_reaction(channel_id, message_id, &emoji)
1617 /// .await?;
1618 /// # Ok(()) }
1619 /// ```
1620 pub const fn create_reaction<'a>(
1621 &'a self,
1622 channel_id: Id<ChannelMarker>,
1623 message_id: Id<MessageMarker>,
1624 emoji: &'a RequestReactionType<'a>,
1625 ) -> CreateReaction<'a> {
1626 CreateReaction::new(self, channel_id, message_id, emoji)
1627 }
1628
1629 /// Delete the current user's (`@me`) reaction on a message.
1630 pub const fn delete_current_user_reaction<'a>(
1631 &'a self,
1632 channel_id: Id<ChannelMarker>,
1633 message_id: Id<MessageMarker>,
1634 emoji: &'a RequestReactionType<'a>,
1635 ) -> DeleteReaction<'a> {
1636 DeleteReaction::new(self, channel_id, message_id, emoji, TargetUser::Current)
1637 }
1638
1639 /// Delete a reaction by a user on a message.
1640 pub const fn delete_reaction<'a>(
1641 &'a self,
1642 channel_id: Id<ChannelMarker>,
1643 message_id: Id<MessageMarker>,
1644 emoji: &'a RequestReactionType<'a>,
1645 user_id: Id<UserMarker>,
1646 ) -> DeleteReaction<'a> {
1647 DeleteReaction::new(self, channel_id, message_id, emoji, TargetUser::Id(user_id))
1648 }
1649
1650 /// Remove all reactions on a message of an emoji.
1651 pub const fn delete_all_reaction<'a>(
1652 &'a self,
1653 channel_id: Id<ChannelMarker>,
1654 message_id: Id<MessageMarker>,
1655 emoji: &'a RequestReactionType<'a>,
1656 ) -> DeleteAllReaction<'a> {
1657 DeleteAllReaction::new(self, channel_id, message_id, emoji)
1658 }
1659
1660 /// Delete all reactions by all users on a message.
1661 pub const fn delete_all_reactions(
1662 &self,
1663 channel_id: Id<ChannelMarker>,
1664 message_id: Id<MessageMarker>,
1665 ) -> DeleteAllReactions<'_> {
1666 DeleteAllReactions::new(self, channel_id, message_id)
1667 }
1668
1669 /// Fire a Typing Start event in the channel.
1670 pub const fn create_typing_trigger(
1671 &self,
1672 channel_id: Id<ChannelMarker>,
1673 ) -> CreateTypingTrigger<'_> {
1674 CreateTypingTrigger::new(self, channel_id)
1675 }
1676
1677 /// Create a DM channel with a user.
1678 pub const fn create_private_channel(
1679 &self,
1680 recipient_id: Id<UserMarker>,
1681 ) -> CreatePrivateChannel<'_> {
1682 CreatePrivateChannel::new(self, recipient_id)
1683 }
1684
1685 /// Get the roles of a guild.
1686 pub const fn roles(&self, guild_id: Id<GuildMarker>) -> GetGuildRoles<'_> {
1687 GetGuildRoles::new(self, guild_id)
1688 }
1689
1690 /// Get a role of a guild.
1691 pub const fn role(&self, guild_id: Id<GuildMarker>, role_id: Id<RoleMarker>) -> GetRole<'_> {
1692 GetRole::new(self, guild_id, role_id)
1693 }
1694
1695 /// Create a role in a guild.
1696 ///
1697 /// # Examples
1698 ///
1699 /// ```no_run
1700 /// # use twilight_http::Client;
1701 /// use twilight_model::id::Id;
1702 ///
1703 /// # #[tokio::main]
1704 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
1705 /// # let client = Client::new("my token".to_owned());
1706 /// let guild_id = Id::new(234);
1707 ///
1708 /// client
1709 /// .create_role(guild_id)
1710 /// .color(0xd90083)
1711 /// .name("Bright Pink")
1712 /// .await?;
1713 /// # Ok(()) }
1714 /// ```
1715 pub const fn create_role(&self, guild_id: Id<GuildMarker>) -> CreateRole<'_> {
1716 CreateRole::new(self, guild_id)
1717 }
1718
1719 /// Delete a role in a guild, by id.
1720 pub const fn delete_role(
1721 &self,
1722 guild_id: Id<GuildMarker>,
1723 role_id: Id<RoleMarker>,
1724 ) -> DeleteRole<'_> {
1725 DeleteRole::new(self, guild_id, role_id)
1726 }
1727
1728 /// Update a role by guild id and its id.
1729 pub const fn update_role(
1730 &self,
1731 guild_id: Id<GuildMarker>,
1732 role_id: Id<RoleMarker>,
1733 ) -> UpdateRole<'_> {
1734 UpdateRole::new(self, guild_id, role_id)
1735 }
1736
1737 /// Modify the position of the roles.
1738 ///
1739 /// The minimum amount of roles to modify, is a swap between two roles.
1740 pub const fn update_role_positions<'a>(
1741 &'a self,
1742 guild_id: Id<GuildMarker>,
1743 roles: &'a [RolePosition],
1744 ) -> UpdateRolePositions<'a> {
1745 UpdateRolePositions::new(self, guild_id, roles)
1746 }
1747
1748 /// Create a new stage instance associated with a stage channel.
1749 ///
1750 /// Requires the user to be a moderator of the stage channel.
1751 ///
1752 /// # Errors
1753 ///
1754 /// Returns an error of type [`ValidationError::StageTopic`] when the topic
1755 /// is not between 1 and 120 characters in length.
1756 ///
1757 /// [`ValidationError::StageTopic`]: twilight_validate::request::ValidationErrorType::StageTopic
1758 pub fn create_stage_instance<'a>(
1759 &'a self,
1760 channel_id: Id<ChannelMarker>,
1761 topic: &'a str,
1762 ) -> CreateStageInstance<'a> {
1763 CreateStageInstance::new(self, channel_id, topic)
1764 }
1765
1766 /// Gets the stage instance associated with a stage channel, if it exists.
1767 pub const fn stage_instance(&self, channel_id: Id<ChannelMarker>) -> GetStageInstance<'_> {
1768 GetStageInstance::new(self, channel_id)
1769 }
1770
1771 /// Update fields of an existing stage instance.
1772 ///
1773 /// Requires the user to be a moderator of the stage channel.
1774 pub const fn update_stage_instance(
1775 &self,
1776 channel_id: Id<ChannelMarker>,
1777 ) -> UpdateStageInstance<'_> {
1778 UpdateStageInstance::new(self, channel_id)
1779 }
1780
1781 /// Delete the stage instance of a stage channel.
1782 ///
1783 /// Requires the user to be a moderator of the stage channel.
1784 pub const fn delete_stage_instance(
1785 &self,
1786 channel_id: Id<ChannelMarker>,
1787 ) -> DeleteStageInstance<'_> {
1788 DeleteStageInstance::new(self, channel_id)
1789 }
1790
1791 /// Create a new guild based on a template.
1792 ///
1793 /// This endpoint can only be used by bots in less than 10 guilds.
1794 ///
1795 /// # Errors
1796 ///
1797 /// Returns an error of type [`ValidationErrorType::TemplateName`] if the
1798 /// name is invalid.
1799 ///
1800 /// [`ValidationErrorType::TemplateName`]: twilight_validate::request::ValidationErrorType::TemplateName
1801 pub fn create_guild_from_template<'a>(
1802 &'a self,
1803 template_code: &'a str,
1804 name: &'a str,
1805 ) -> CreateGuildFromTemplate<'a> {
1806 CreateGuildFromTemplate::new(self, template_code, name)
1807 }
1808
1809 /// Create a template from the current state of the guild.
1810 ///
1811 /// Requires the `MANAGE_GUILD` permission. The name must be at least 1 and
1812 /// at most 100 characters in length.
1813 ///
1814 /// # Errors
1815 ///
1816 /// Returns an error of type [`ValidationErrorType::TemplateName`] if the
1817 /// name is invalid.
1818 ///
1819 /// [`ValidationErrorType::TemplateName`]: twilight_validate::request::ValidationErrorType::TemplateName
1820 pub fn create_template<'a>(
1821 &'a self,
1822 guild_id: Id<GuildMarker>,
1823 name: &'a str,
1824 ) -> CreateTemplate<'a> {
1825 CreateTemplate::new(self, guild_id, name)
1826 }
1827
1828 /// Delete a template by ID and code.
1829 pub const fn delete_template<'a>(
1830 &'a self,
1831 guild_id: Id<GuildMarker>,
1832 template_code: &'a str,
1833 ) -> DeleteTemplate<'a> {
1834 DeleteTemplate::new(self, guild_id, template_code)
1835 }
1836
1837 /// Get a template by its code.
1838 pub const fn get_template<'a>(&'a self, template_code: &'a str) -> GetTemplate<'a> {
1839 GetTemplate::new(self, template_code)
1840 }
1841
1842 /// Get a list of templates in a guild, by ID.
1843 pub const fn get_templates(&self, guild_id: Id<GuildMarker>) -> GetTemplates<'_> {
1844 GetTemplates::new(self, guild_id)
1845 }
1846
1847 /// Sync a template to the current state of the guild, by ID and code.
1848 pub const fn sync_template<'a>(
1849 &'a self,
1850 guild_id: Id<GuildMarker>,
1851 template_code: &'a str,
1852 ) -> SyncTemplate<'a> {
1853 SyncTemplate::new(self, guild_id, template_code)
1854 }
1855
1856 /// Update the template's metadata, by ID and code.
1857 pub const fn update_template<'a>(
1858 &'a self,
1859 guild_id: Id<GuildMarker>,
1860 template_code: &'a str,
1861 ) -> UpdateTemplate<'a> {
1862 UpdateTemplate::new(self, guild_id, template_code)
1863 }
1864
1865 /// Returns all active threads in the guild.
1866 ///
1867 /// Includes public and private threads. Threads are ordered by their ID in
1868 /// descending order.
1869 ///
1870 /// # Examples
1871 ///
1872 /// ```no_run
1873 /// # #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> {
1874 /// use twilight_http::Client;
1875 /// use twilight_model::id::Id;
1876 ///
1877 /// let client = Client::new("my token".to_owned());
1878 /// let guild_id = Id::new(234);
1879 ///
1880 /// let threads = client.active_threads(guild_id).await?.model().await?;
1881 /// # Ok(()) }
1882 /// ```
1883 pub const fn active_threads(&self, guild_id: Id<GuildMarker>) -> GetActiveThreads<'_> {
1884 GetActiveThreads::new(self, guild_id)
1885 }
1886
1887 /// Add another member to a thread.
1888 ///
1889 /// Requires the ability to send messages in the thread, and that the thread
1890 /// is not archived.
1891 pub const fn add_thread_member(
1892 &self,
1893 channel_id: Id<ChannelMarker>,
1894 user_id: Id<UserMarker>,
1895 ) -> AddThreadMember<'_> {
1896 AddThreadMember::new(self, channel_id, user_id)
1897 }
1898
1899 /// Start a thread in a forum channel.
1900 pub const fn create_forum_thread<'a>(
1901 &'a self,
1902 channel_id: Id<ChannelMarker>,
1903 name: &'a str,
1904 ) -> CreateForumThread<'a> {
1905 CreateForumThread::new(self, channel_id, name)
1906 }
1907
1908 /// Start a thread that is not connected to a message.
1909 ///
1910 /// Automatic archive durations are not locked behind the guild's boost
1911 /// level.
1912 ///
1913 /// To make a [`PrivateThread`], the guild must also have the
1914 /// `PRIVATE_THREADS` feature.
1915 ///
1916 /// # Errors
1917 ///
1918 /// Returns an error of type [`NameInvalid`] if the channel's name's length is
1919 /// incorrect.
1920 ///
1921 /// Returns an error of type [`TypeInvalid`] if the channel is not a thread.
1922 ///
1923 /// [`NameInvalid`]: twilight_validate::channel::ChannelValidationErrorType::NameInvalid
1924 /// [`PrivateThread`]: twilight_model::channel::ChannelType::PrivateThread
1925 /// [`TypeInvalid`]: twilight_validate::channel::ChannelValidationErrorType::TypeInvalid
1926 pub fn create_thread<'a>(
1927 &'a self,
1928 channel_id: Id<ChannelMarker>,
1929 name: &'a str,
1930 kind: ChannelType,
1931 ) -> CreateThread<'a> {
1932 CreateThread::new(self, channel_id, name, kind)
1933 }
1934
1935 /// Create a new thread from an existing message.
1936 ///
1937 /// When called on a [`GuildText`] channel, this creates a
1938 /// [`PublicThread`].
1939 ///
1940 /// When called on a [`GuildAnnouncement`] channel, this creates a
1941 /// [`AnnouncementThread`].
1942 ///
1943 /// Automatic archive durations are not locked behind the guild's boost
1944 /// level.
1945 ///
1946 /// The thread's ID will be the same as its parent message. This ensures
1947 /// only one thread can be created per message.
1948 ///
1949 /// # Errors
1950 ///
1951 /// Returns an error of type [`NameInvalid`] if the channel's name's length is
1952 /// incorrect.
1953 ///
1954 /// Returns an error of type [`TypeInvalid`] if the channel is not a thread.
1955 ///
1956 /// [`AnnouncementThread`]: twilight_model::channel::ChannelType::AnnouncementThread
1957 /// [`GuildAnnouncement`]: twilight_model::channel::ChannelType::GuildAnnouncement
1958 /// [`GuildText`]: twilight_model::channel::ChannelType::GuildText
1959 /// [`NameInvalid`]: twilight_validate::channel::ChannelValidationErrorType::NameInvalid
1960 /// [`PublicThread`]: twilight_model::channel::ChannelType::PublicThread
1961 /// [`TypeInvalid`]: twilight_validate::channel::ChannelValidationErrorType::TypeInvalid
1962 pub fn create_thread_from_message<'a>(
1963 &'a self,
1964 channel_id: Id<ChannelMarker>,
1965 message_id: Id<MessageMarker>,
1966 name: &'a str,
1967 ) -> CreateThreadFromMessage<'a> {
1968 CreateThreadFromMessage::new(self, channel_id, message_id, name)
1969 }
1970
1971 /// Add the current user to a thread.
1972 pub const fn join_thread(&self, channel_id: Id<ChannelMarker>) -> JoinThread<'_> {
1973 JoinThread::new(self, channel_id)
1974 }
1975
1976 /// Returns archived private threads in the channel that the current user
1977 /// has joined.
1978 ///
1979 /// Threads are ordered by their ID in descending order.
1980 pub const fn joined_private_archived_threads(
1981 &self,
1982 channel_id: Id<ChannelMarker>,
1983 ) -> GetJoinedPrivateArchivedThreads<'_> {
1984 GetJoinedPrivateArchivedThreads::new(self, channel_id)
1985 }
1986
1987 /// Remove the current user from a thread.
1988 ///
1989 /// Requires that the thread is not archived.
1990 pub const fn leave_thread(&self, channel_id: Id<ChannelMarker>) -> LeaveThread<'_> {
1991 LeaveThread::new(self, channel_id)
1992 }
1993
1994 /// Returns archived private threads in the channel.
1995 ///
1996 /// Requires both [`READ_MESSAGE_HISTORY`] and [`MANAGE_THREADS`].
1997 ///
1998 /// [`MANAGE_THREADS`]: twilight_model::guild::Permissions::MANAGE_THREADS
1999 /// [`READ_MESSAGE_HISTORY`]: twilight_model::guild::Permissions::READ_MESSAGE_HISTORY
2000 pub const fn private_archived_threads(
2001 &self,
2002 channel_id: Id<ChannelMarker>,
2003 ) -> GetPrivateArchivedThreads<'_> {
2004 GetPrivateArchivedThreads::new(self, channel_id)
2005 }
2006
2007 /// Returns archived public threads in the channel.
2008 ///
2009 /// Requires the [`READ_MESSAGE_HISTORY`] permission.
2010 ///
2011 /// Threads are ordered by [`archive_timestamp`] in descending order.
2012 ///
2013 /// When called in a [`GuildText`] channel, returns [`PublicThread`]s.
2014 ///
2015 /// When called in a [`GuildAnnouncement`] channel, returns [`AnnouncementThread`]s.
2016 ///
2017 /// [`AnnouncementThread`]: twilight_model::channel::ChannelType::AnnouncementThread
2018 /// [`archive_timestamp`]: twilight_model::channel::thread::ThreadMetadata::archive_timestamp
2019 /// [`GuildAnnouncement`]: twilight_model::channel::ChannelType::GuildAnnouncement
2020 /// [`GuildText`]: twilight_model::channel::ChannelType::GuildText
2021 /// [`PublicThread`]: twilight_model::channel::ChannelType::PublicThread
2022 /// [`READ_MESSAGE_HISTORY`]: twilight_model::guild::Permissions::READ_MESSAGE_HISTORY
2023 pub const fn public_archived_threads(
2024 &self,
2025 channel_id: Id<ChannelMarker>,
2026 ) -> GetPublicArchivedThreads<'_> {
2027 GetPublicArchivedThreads::new(self, channel_id)
2028 }
2029
2030 /// Remove another member from a thread.
2031 ///
2032 /// Requires that the thread is not archived.
2033 ///
2034 /// Requires the [`MANAGE_THREADS`] permission, unless both the thread is a
2035 /// [`PrivateThread`], and the current user is the creator of the
2036 /// thread.
2037 ///
2038 /// [`MANAGE_THREADS`]: twilight_model::guild::Permissions::MANAGE_THREADS
2039 /// [`PrivateThread`]: twilight_model::channel::ChannelType::PrivateThread
2040 pub const fn remove_thread_member(
2041 &self,
2042 channel_id: Id<ChannelMarker>,
2043 user_id: Id<UserMarker>,
2044 ) -> RemoveThreadMember<'_> {
2045 RemoveThreadMember::new(self, channel_id, user_id)
2046 }
2047
2048 /// Returns a [`ThreadMember`] in a thread.
2049 ///
2050 /// [`ThreadMember`]: twilight_model::channel::thread::ThreadMember
2051 pub const fn thread_member(
2052 &self,
2053 channel_id: Id<ChannelMarker>,
2054 user_id: Id<UserMarker>,
2055 ) -> GetThreadMember<'_> {
2056 GetThreadMember::new(self, channel_id, user_id)
2057 }
2058
2059 /// Returns the [`ThreadMember`]s of the thread.
2060 ///
2061 /// [`ThreadMember`]: twilight_model::channel::thread::ThreadMember
2062 pub const fn thread_members(&self, channel_id: Id<ChannelMarker>) -> GetThreadMembers<'_> {
2063 GetThreadMembers::new(self, channel_id)
2064 }
2065
2066 /// Update a thread.
2067 ///
2068 /// All fields are optional. The minimum length of the name is 1 UTF-16
2069 /// characters and the maximum is 100 UTF-16 characters.
2070 pub const fn update_thread(&self, channel_id: Id<ChannelMarker>) -> UpdateThread<'_> {
2071 UpdateThread::new(self, channel_id)
2072 }
2073
2074 /// Get a user's information by id.
2075 pub const fn user(&self, user_id: Id<UserMarker>) -> GetUser<'_> {
2076 GetUser::new(self, user_id)
2077 }
2078
2079 /// Get voice state of a user in a guild.
2080 ///
2081 /// # Caveats
2082 ///
2083 /// - User must already have joined a voice/stage channel in this guild.
2084 pub const fn user_voice_state(
2085 &self,
2086 guild_id: Id<GuildMarker>,
2087 user_id: Id<UserMarker>,
2088 ) -> GetUserVoiceState<'_> {
2089 GetUserVoiceState::new(self, guild_id, user_id)
2090 }
2091
2092 /// Update another user's voice state.
2093 ///
2094 /// # Caveats
2095 ///
2096 /// - `channel_id` must currently point to a stage channel.
2097 /// - User must already have joined `channel_id`.
2098 pub const fn update_user_voice_state(
2099 &self,
2100 guild_id: Id<GuildMarker>,
2101 user_id: Id<UserMarker>,
2102 channel_id: Id<ChannelMarker>,
2103 ) -> UpdateUserVoiceState<'_> {
2104 UpdateUserVoiceState::new(self, guild_id, user_id, channel_id)
2105 }
2106
2107 /// Get a list of voice regions that can be used when creating a guild.
2108 pub const fn voice_regions(&self) -> GetVoiceRegions<'_> {
2109 GetVoiceRegions::new(self)
2110 }
2111
2112 /// Get a webhook by ID.
2113 pub const fn webhook(&self, id: Id<WebhookMarker>) -> GetWebhook<'_> {
2114 GetWebhook::new(self, id)
2115 }
2116
2117 /// Create a webhook in a channel.
2118 ///
2119 /// # Examples
2120 ///
2121 /// ```no_run
2122 /// # use twilight_http::Client;
2123 /// # use twilight_model::id::Id;
2124 /// #
2125 /// # #[tokio::main]
2126 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
2127 /// # let client = Client::new("my token".to_owned());
2128 /// let channel_id = Id::new(123);
2129 ///
2130 /// let webhook = client.create_webhook(channel_id, "Twily Bot").await?;
2131 /// # Ok(()) }
2132 /// ```
2133 ///
2134 /// # Errors
2135 ///
2136 /// Returns an error of type [`WebhookUsername`] if the webhook's name is
2137 /// invalid.
2138 ///
2139 /// [`WebhookUsername`]: twilight_validate::request::ValidationErrorType::WebhookUsername
2140 pub fn create_webhook<'a>(
2141 &'a self,
2142 channel_id: Id<ChannelMarker>,
2143 name: &'a str,
2144 ) -> CreateWebhook<'a> {
2145 CreateWebhook::new(self, channel_id, name)
2146 }
2147
2148 /// Delete a webhook by its ID.
2149 pub const fn delete_webhook(&self, id: Id<WebhookMarker>) -> DeleteWebhook<'_> {
2150 DeleteWebhook::new(self, id)
2151 }
2152
2153 /// Update a webhook by ID.
2154 pub const fn update_webhook(&self, webhook_id: Id<WebhookMarker>) -> UpdateWebhook<'_> {
2155 UpdateWebhook::new(self, webhook_id)
2156 }
2157
2158 /// Update a webhook, with a token, by ID.
2159 pub const fn update_webhook_with_token<'a>(
2160 &'a self,
2161 webhook_id: Id<WebhookMarker>,
2162 token: &'a str,
2163 ) -> UpdateWebhookWithToken<'a> {
2164 UpdateWebhookWithToken::new(self, webhook_id, token)
2165 }
2166
2167 /// Execute a webhook, sending a message to its channel.
2168 ///
2169 /// The message must include at least one of [`attachments`], [`components`]
2170 /// [`content`], or [`embeds`].
2171 ///
2172 /// # Examples
2173 ///
2174 /// ```no_run
2175 /// # #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> {
2176 /// use twilight_http::Client;
2177 /// use twilight_model::id::Id;
2178 ///
2179 /// let client = Client::new("my token".to_owned());
2180 /// let id = Id::new(432);
2181 ///
2182 /// let webhook = client
2183 /// .execute_webhook(id, "webhook token")
2184 /// .content("Pinkie...")
2185 /// .await?;
2186 /// # Ok(()) }
2187 /// ```
2188 ///
2189 /// [`attachments`]: ExecuteWebhook::attachments
2190 /// [`components`]: ExecuteWebhook::components
2191 /// [`content`]: ExecuteWebhook::content
2192 /// [`embeds`]: ExecuteWebhook::embeds
2193 pub const fn execute_webhook<'a>(
2194 &'a self,
2195 webhook_id: Id<WebhookMarker>,
2196 token: &'a str,
2197 ) -> ExecuteWebhook<'a> {
2198 ExecuteWebhook::new(self, webhook_id, token)
2199 }
2200
2201 /// Get a webhook message by webhook ID, token, and message ID.
2202 pub const fn webhook_message<'a>(
2203 &'a self,
2204 webhook_id: Id<WebhookMarker>,
2205 token: &'a str,
2206 message_id: Id<MessageMarker>,
2207 ) -> GetWebhookMessage<'a> {
2208 GetWebhookMessage::new(self, webhook_id, token, message_id)
2209 }
2210
2211 /// Update a message executed by a webhook.
2212 ///
2213 /// You can pass [`None`] to any of the methods to remove the associated
2214 /// field. Pass [`None`] to [`content`] to remove the content. You must
2215 /// ensure that the message still contains at least one of [`attachments`],
2216 /// [`components`], [`content`], or [`embeds`].
2217 ///
2218 /// # Examples
2219 ///
2220 /// ```no_run
2221 /// # #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> {
2222 /// use twilight_http::Client;
2223 /// use twilight_model::id::Id;
2224 ///
2225 /// let client = Client::new("token".to_owned());
2226 /// client
2227 /// .update_webhook_message(Id::new(1), "token here", Id::new(2))
2228 /// .content(Some("new message content"))
2229 /// .await?;
2230 /// # Ok(()) }
2231 /// ```
2232 ///
2233 /// [`attachments`]: UpdateWebhookMessage::attachments
2234 /// [`components`]: UpdateWebhookMessage::components
2235 /// [`content`]: UpdateWebhookMessage::content
2236 /// [`embeds`]: UpdateWebhookMessage::embeds
2237 pub const fn update_webhook_message<'a>(
2238 &'a self,
2239 webhook_id: Id<WebhookMarker>,
2240 token: &'a str,
2241 message_id: Id<MessageMarker>,
2242 ) -> UpdateWebhookMessage<'a> {
2243 UpdateWebhookMessage::new(self, webhook_id, token, message_id)
2244 }
2245
2246 /// Delete a message executed by a webhook.
2247 ///
2248 /// # Examples
2249 ///
2250 /// ```no_run
2251 /// # use twilight_http::Client;
2252 /// use twilight_model::id::Id;
2253 ///
2254 /// # #[tokio::main]
2255 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
2256 /// # let client = Client::new("token".to_owned());
2257 /// client
2258 /// .delete_webhook_message(Id::new(1), "token here", Id::new(2))
2259 /// .await?;
2260 /// # Ok(()) }
2261 /// ```
2262 pub const fn delete_webhook_message<'a>(
2263 &'a self,
2264 webhook_id: Id<WebhookMarker>,
2265 token: &'a str,
2266 message_id: Id<MessageMarker>,
2267 ) -> DeleteWebhookMessage<'a> {
2268 DeleteWebhookMessage::new(self, webhook_id, token, message_id)
2269 }
2270
2271 /// Delete a scheduled event in a guild.
2272 ///
2273 /// # Examples
2274 ///
2275 /// ```no_run
2276 /// # use twilight_http::Client;
2277 /// # use twilight_model::id::Id;
2278 /// # #[tokio::main]
2279 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
2280 /// # let client = Client::new("token".to_owned());
2281 /// let guild_id = Id::new(1);
2282 /// let scheduled_event_id = Id::new(2);
2283 ///
2284 /// client
2285 /// .delete_guild_scheduled_event(guild_id, scheduled_event_id)
2286 /// .await?;
2287 /// # Ok(()) }
2288 /// ```
2289 pub const fn delete_guild_scheduled_event(
2290 &self,
2291 guild_id: Id<GuildMarker>,
2292 scheduled_event_id: Id<ScheduledEventMarker>,
2293 ) -> DeleteGuildScheduledEvent<'_> {
2294 DeleteGuildScheduledEvent::new(self, guild_id, scheduled_event_id)
2295 }
2296
2297 /// Create a scheduled event in a guild.
2298 ///
2299 /// Once a guild is selected, you must choose one of three event types to
2300 /// create. The request builders will ensure you provide the correct data to
2301 /// Discord. See [Discord Docs/Create Guild Scheduled Event].
2302 ///
2303 /// The name must be between 1 and 100 characters in length. For external
2304 /// events, the location must be between 1 and 100 characters in length.
2305 ///
2306 /// # Examples
2307 ///
2308 /// Create an event in a stage instance:
2309 ///
2310 /// ```no_run
2311 /// # use twilight_http::Client;
2312 /// use twilight_model::{guild::scheduled_event::PrivacyLevel, id::Id, util::Timestamp};
2313 /// # #[tokio::main]
2314 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
2315 /// # let client = Client::new("token".to_owned());
2316 /// let guild_id = Id::new(1);
2317 /// let channel_id = Id::new(2);
2318 /// let garfield_start_time = Timestamp::parse("2022-01-01T14:00:00+00:00")?;
2319 ///
2320 /// client
2321 /// .create_guild_scheduled_event(guild_id, PrivacyLevel::GuildOnly)
2322 /// .stage_instance(
2323 /// channel_id,
2324 /// "Garfield Appreciation Hour",
2325 /// &garfield_start_time,
2326 /// )
2327 /// .description("Discuss: How important is Garfield to You?")
2328 /// .await?;
2329 /// # Ok(()) }
2330 /// ```
2331 ///
2332 /// Create an external event:
2333 ///
2334 /// ```no_run
2335 /// # use twilight_http::Client;
2336 /// use twilight_model::{guild::scheduled_event::PrivacyLevel, id::Id, util::Timestamp};
2337 /// # #[tokio::main]
2338 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
2339 /// # let client = Client::new("token".to_owned());
2340 /// let guild_id = Id::new(1);
2341 /// let garfield_con_start_time = Timestamp::parse("2022-01-04T08:00:00+00:00")?;
2342 /// let garfield_con_end_time = Timestamp::parse("2022-01-06T17:00:00+00:00")?;
2343 ///
2344 /// client
2345 /// .create_guild_scheduled_event(guild_id, PrivacyLevel::GuildOnly)
2346 /// .external(
2347 /// "Garfield Con 2022",
2348 /// "Baltimore Convention Center",
2349 /// &garfield_con_start_time,
2350 /// &garfield_con_end_time,
2351 /// )
2352 /// .description(
2353 /// "In a spiritual successor to BronyCon, Garfield fans from \
2354 /// around the globe celebrate all things related to the loveable cat.",
2355 /// )
2356 /// .await?;
2357 /// # Ok(()) }
2358 /// ```
2359 ///
2360 /// [Discord Docs/Create Guild Scheduled Event]: https://discord.com/developers/docs/resources/guild-scheduled-event#create-guild-scheduled-event
2361 pub const fn create_guild_scheduled_event(
2362 &self,
2363 guild_id: Id<GuildMarker>,
2364 privacy_level: PrivacyLevel,
2365 ) -> CreateGuildScheduledEvent<'_> {
2366 CreateGuildScheduledEvent::new(self, guild_id, privacy_level)
2367 }
2368
2369 /// Get a scheduled event in a guild.
2370 pub const fn guild_scheduled_event(
2371 &self,
2372 guild_id: Id<GuildMarker>,
2373 scheduled_event_id: Id<ScheduledEventMarker>,
2374 ) -> GetGuildScheduledEvent<'_> {
2375 GetGuildScheduledEvent::new(self, guild_id, scheduled_event_id)
2376 }
2377
2378 /// Get a list of users subscribed to a scheduled event.
2379 ///
2380 /// Users are returned in ascending order by `user_id`. [`before`] and
2381 /// [`after`] both take a user id. If both are specified, only [`before`] is
2382 /// respected. The default [`limit`] is 100. See
2383 /// [Discord Docs/Get Guild Scheduled Event Users].
2384 ///
2385 /// [`after`]: GetGuildScheduledEventUsers::after
2386 /// [`before`]: GetGuildScheduledEventUsers::before
2387 /// [`limit`]: GetGuildScheduledEventUsers::limit
2388 /// [Discord Docs/Get Guild Scheduled Event Users]: https://discord.com/developers/docs/resources/guild-scheduled-event#get-guild-scheduled-event-users
2389 pub const fn guild_scheduled_event_users(
2390 &self,
2391 guild_id: Id<GuildMarker>,
2392 scheduled_event_id: Id<ScheduledEventMarker>,
2393 ) -> GetGuildScheduledEventUsers<'_> {
2394 GetGuildScheduledEventUsers::new(self, guild_id, scheduled_event_id)
2395 }
2396
2397 /// Get a list of scheduled events in a guild.
2398 pub const fn guild_scheduled_events(
2399 &self,
2400 guild_id: Id<GuildMarker>,
2401 ) -> GetGuildScheduledEvents<'_> {
2402 GetGuildScheduledEvents::new(self, guild_id)
2403 }
2404
2405 /// Update a scheduled event in a guild.
2406 ///
2407 /// This endpoint supports changing the type of event. When changing the
2408 /// entity type to either [`EntityType::StageInstance`] or
2409 /// [`EntityType::Voice`], an [`Id<ChannelMarker>`] must be provided if it
2410 /// does not already exist.
2411 ///
2412 /// When changing the entity type to [`EntityType::External`], the
2413 /// `channel_id` field is cleared and the [`channel_id`] method has no
2414 /// effect. Additionally, you must set a location with [`location`].
2415 ///
2416 /// [`EntityType::External`]: twilight_model::guild::scheduled_event::EntityType::External
2417 /// [`EntityType::StageInstance`]: twilight_model::guild::scheduled_event::EntityType::StageInstance
2418 /// [`EntityType::Voice`]: twilight_model::guild::scheduled_event::EntityType::Voice
2419 /// [`channel_id`]: UpdateGuildScheduledEvent::channel_id
2420 /// [`location`]: UpdateGuildScheduledEvent::location
2421 pub const fn update_guild_scheduled_event(
2422 &self,
2423 guild_id: Id<GuildMarker>,
2424 scheduled_event_id: Id<ScheduledEventMarker>,
2425 ) -> UpdateGuildScheduledEvent<'_> {
2426 UpdateGuildScheduledEvent::new(self, guild_id, scheduled_event_id)
2427 }
2428
2429 /// Returns a single sticker by its ID.
2430 ///
2431 /// # Examples
2432 ///
2433 /// ```no_run
2434 /// use twilight_http::Client;
2435 /// use twilight_model::id::Id;
2436 ///
2437 /// # #[tokio::main]
2438 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
2439 /// let client = Client::new("my token".to_owned());
2440 ///
2441 /// let id = Id::new(123);
2442 /// let sticker = client.sticker(id).await?.model().await?;
2443 ///
2444 /// println!("{sticker:#?}");
2445 /// # Ok(()) }
2446 /// ```
2447 pub const fn sticker(&self, sticker_id: Id<StickerMarker>) -> GetSticker<'_> {
2448 GetSticker::new(self, sticker_id)
2449 }
2450
2451 /// Returns a list of sticker packs available to Nitro subscribers.
2452 ///
2453 /// # Examples
2454 ///
2455 /// ```no_run
2456 /// use twilight_http::Client;
2457 ///
2458 /// # #[tokio::main]
2459 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
2460 /// let client = Client::new("my token".to_owned());
2461 ///
2462 /// let packs = client.nitro_sticker_packs().await?.model().await?;
2463 ///
2464 /// println!("{}", packs.sticker_packs.len());
2465 /// # Ok(()) }
2466 /// ```
2467 pub const fn nitro_sticker_packs(&self) -> GetNitroStickerPacks<'_> {
2468 GetNitroStickerPacks::new(self)
2469 }
2470
2471 /// Returns a list of stickers in a guild.
2472 ///
2473 /// # Examples
2474 ///
2475 /// ```no_run
2476 /// use twilight_http::Client;
2477 /// use twilight_model::id::Id;
2478 ///
2479 /// # #[tokio::main]
2480 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
2481 /// let client = Client::new("my token".to_owned());
2482 ///
2483 /// let guild_id = Id::new(1);
2484 /// let stickers = client.guild_stickers(guild_id).await?.models().await?;
2485 ///
2486 /// println!("{}", stickers.len());
2487 /// # Ok(()) }
2488 /// ```
2489 pub const fn guild_stickers(&self, guild_id: Id<GuildMarker>) -> GetGuildStickers<'_> {
2490 GetGuildStickers::new(self, guild_id)
2491 }
2492
2493 /// Returns a guild sticker by the guild's ID and the sticker's ID.
2494 ///
2495 /// # Examples
2496 ///
2497 /// ```no_run
2498 /// use twilight_http::Client;
2499 /// use twilight_model::id::Id;
2500 ///
2501 /// # #[tokio::main]
2502 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
2503 /// let client = Client::new("my token".to_owned());
2504 ///
2505 /// let guild_id = Id::new(1);
2506 /// let sticker_id = Id::new(2);
2507 /// let sticker = client
2508 /// .guild_sticker(guild_id, sticker_id)
2509 /// .await?
2510 /// .model()
2511 /// .await?;
2512 ///
2513 /// println!("{sticker:#?}");
2514 /// # Ok(()) }
2515 /// ```
2516 pub const fn guild_sticker(
2517 &self,
2518 guild_id: Id<GuildMarker>,
2519 sticker_id: Id<StickerMarker>,
2520 ) -> GetGuildSticker<'_> {
2521 GetGuildSticker::new(self, guild_id, sticker_id)
2522 }
2523
2524 /// Creates a sticker in a guild, and returns the created sticker.
2525 ///
2526 /// # Examples
2527 ///
2528 /// ```no_run
2529 /// use twilight_http::Client;
2530 /// use twilight_model::id::Id;
2531 ///
2532 /// # #[tokio::main]
2533 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
2534 /// let client = Client::new("my token".to_owned());
2535 ///
2536 /// let guild_id = Id::new(1);
2537 /// let sticker = client
2538 /// .create_guild_sticker(
2539 /// guild_id,
2540 /// &"sticker name",
2541 /// &"sticker description",
2542 /// &"sticker,tags",
2543 /// &[23, 23, 23, 23],
2544 /// )
2545 /// .await?
2546 /// .model()
2547 /// .await?;
2548 ///
2549 /// println!("{sticker:#?}");
2550 /// # Ok(()) }
2551 /// ```
2552 ///
2553 /// # Errors
2554 ///
2555 /// Returns an error of type [`DescriptionInvalid`] if the length is invalid.
2556 ///
2557 /// Returns an error of type [`NameInvalid`] if the length is invalid.
2558 ///
2559 /// Returns an error of type [`TagsInvalid`] if the length is invalid.
2560 ///
2561 /// [`DescriptionInvalid`]: twilight_validate::sticker::StickerValidationErrorType::DescriptionInvalid
2562 /// [`NameInvalid`]: twilight_validate::sticker::StickerValidationErrorType::NameInvalid
2563 /// [`TagsInvalid`]: twilight_validate::sticker::StickerValidationErrorType::TagsInvalid
2564 pub fn create_guild_sticker<'a>(
2565 &'a self,
2566 guild_id: Id<GuildMarker>,
2567 name: &'a str,
2568 description: &'a str,
2569 tags: &'a str,
2570 file: &'a [u8],
2571 ) -> CreateGuildSticker<'a> {
2572 CreateGuildSticker::new(self, guild_id, name, description, tags, file)
2573 }
2574
2575 /// Updates a sticker in a guild, and returns the updated sticker.
2576 ///
2577 /// # Examples
2578 ///
2579 /// ```no_run
2580 /// use twilight_http::Client;
2581 /// use twilight_model::id::Id;
2582 ///
2583 /// # #[tokio::main]
2584 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
2585 /// let client = Client::new("my token".to_owned());
2586 ///
2587 /// let guild_id = Id::new(1);
2588 /// let sticker_id = Id::new(2);
2589 /// let sticker = client
2590 /// .update_guild_sticker(guild_id, sticker_id)
2591 /// .description("new description")
2592 /// .await?
2593 /// .model()
2594 /// .await?;
2595 ///
2596 /// println!("{sticker:#?}");
2597 /// # Ok(()) }
2598 /// ```
2599 pub const fn update_guild_sticker(
2600 &self,
2601 guild_id: Id<GuildMarker>,
2602 sticker_id: Id<StickerMarker>,
2603 ) -> UpdateGuildSticker<'_> {
2604 UpdateGuildSticker::new(self, guild_id, sticker_id)
2605 }
2606
2607 /// Deletes a guild sticker by the ID of the guild and its ID.
2608 ///
2609 /// # Examples
2610 ///
2611 /// ```no_run
2612 /// use twilight_http::Client;
2613 /// use twilight_model::id::Id;
2614 ///
2615 /// # #[tokio::main]
2616 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
2617 /// let client = Client::new("my token".to_owned());
2618 ///
2619 /// let guild_id = Id::new(1);
2620 /// let sticker_id = Id::new(2);
2621 ///
2622 /// client.delete_guild_sticker(guild_id, sticker_id).await?;
2623 /// # Ok(()) }
2624 /// ```
2625 pub const fn delete_guild_sticker(
2626 &self,
2627 guild_id: Id<GuildMarker>,
2628 sticker_id: Id<StickerMarker>,
2629 ) -> DeleteGuildSticker<'_> {
2630 DeleteGuildSticker::new(self, guild_id, sticker_id)
2631 }
2632
2633 /// Creates a test entitlement to a given SKU for a given guild or user. Discord
2634 /// will act as though that user or guild has entitlement to your premium offering.
2635 ///
2636 /// # Examples
2637 ///
2638 /// ```no_run
2639 /// use twilight_http::{Client, request::application::monetization::CreateTestEntitlementOwner};
2640 /// use twilight_model::id::Id;
2641 ///
2642 /// # #[tokio::main]
2643 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
2644 /// let client = Client::new("my token".to_owned());
2645 ///
2646 /// let application_id = Id::new(1);
2647 /// let sku_id = Id::new(2);
2648 /// let owner = CreateTestEntitlementOwner::Guild(Id::new(3));
2649 ///
2650 /// client.create_test_entitlement(
2651 /// application_id,
2652 /// sku_id,
2653 /// owner,
2654 /// ).await?;
2655 ///
2656 /// # Ok(()) }
2657 pub const fn create_test_entitlement(
2658 &self,
2659 application_id: Id<ApplicationMarker>,
2660 sku_id: Id<SkuMarker>,
2661 owner: CreateTestEntitlementOwner,
2662 ) -> CreateTestEntitlement<'_> {
2663 CreateTestEntitlement::new(self, application_id, sku_id, owner)
2664 }
2665
2666 /// Ends a poll in a channel.
2667 ///
2668 /// # Examples
2669 ///
2670 /// ```no_run
2671 /// use twilight_http::Client;
2672 /// use twilight_model::id::Id;
2673 ///
2674 /// # #[tokio::main]
2675 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
2676 /// let client = Client::new("my token".to_owned());
2677 ///
2678 /// let channel_id = Id::new(1);
2679 /// let message_id = Id::new(2);
2680 ///
2681 /// client.end_poll(channel_id, message_id).await?;
2682 /// # Ok(()) }
2683 /// ```
2684 pub const fn end_poll(
2685 &self,
2686 channel_id: Id<ChannelMarker>,
2687 message_id: Id<MessageMarker>,
2688 ) -> EndPoll<'_> {
2689 EndPoll::new(self, channel_id, message_id)
2690 }
2691
2692 /// Deletes a currently-active test entitlement. Discord will act as though that user or
2693 /// guild no longer has entitlement to your premium offering.
2694 ///
2695 /// # Examples
2696 ///
2697 /// ```no_run
2698 /// use twilight_http::Client;
2699 /// use twilight_model::id::Id;
2700 ///
2701 /// # #[tokio::main]
2702 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
2703 /// let client = Client::new("my token".to_owned());
2704 ///
2705 /// let application_id = Id::new(1);
2706 /// let entitlement_id = Id::new(2);
2707 ///
2708 /// client.delete_test_entitlement(
2709 /// application_id,
2710 /// entitlement_id,
2711 /// ).await?;
2712 ///
2713 /// # Ok(()) }
2714 pub const fn delete_test_entitlement(
2715 &self,
2716 application_id: Id<ApplicationMarker>,
2717 entitlement_id: Id<EntitlementMarker>,
2718 ) -> DeleteTestEntitlement<'_> {
2719 DeleteTestEntitlement::new(self, application_id, entitlement_id)
2720 }
2721
2722 /// /// Get the voters for an answer in a poll.
2723 ///
2724 /// # Examples
2725 ///
2726 /// ```no_run
2727 /// use twilight_http::Client;
2728 /// use twilight_model::id::Id;
2729 ///
2730 /// # #[tokio::main]
2731 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
2732 /// let client = Client::new("my token".to_owned());
2733 ///
2734 /// let channel_id = Id::new(1);
2735 /// let message_id = Id::new(2);
2736 /// let answer_id = 1;
2737 ///
2738 /// let voters = client.get_answer_voters(channel_id, message_id, answer_id).await?;
2739 ///
2740 /// println!("{:?}", voters);
2741 /// # Ok(()) }
2742 pub const fn get_answer_voters(
2743 &self,
2744 channel_id: Id<ChannelMarker>,
2745 message_id: Id<MessageMarker>,
2746 answer_id: u8,
2747 ) -> GetAnswerVoters<'_> {
2748 GetAnswerVoters::new(self, channel_id, message_id, answer_id)
2749 }
2750
2751 /// Returns all SKUs for a given application.
2752 ///
2753 /// # Examples
2754 ///
2755 /// ```no_run
2756 /// use twilight_http::Client;
2757 /// use twilight_model::id::Id;
2758 ///
2759 /// # #[tokio::main]
2760 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
2761 /// let client = Client::new("my token".to_owned());
2762 ///
2763 /// let application_id = Id::new(1);
2764 ///
2765 /// let skus = client.get_skus(application_id).await?;
2766 ///
2767 /// # Ok(()) }
2768 pub const fn get_skus(&self, application_id: Id<ApplicationMarker>) -> GetSKUs<'_> {
2769 GetSKUs::new(self, application_id)
2770 }
2771
2772 /// Gets all emojis associated with an application
2773 ///
2774 /// # Examples
2775 ///
2776 /// ```no_run
2777 /// use twilight_http::Client;
2778 /// use twilight_model::id::Id;
2779 ///
2780 /// # #[tokio::main]
2781 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
2782 /// let client = Client::new("my token".to_owned());
2783 ///
2784 /// let application_id = Id::new(1);
2785 ///
2786 /// let emojis = client.get_application_emojis(application_id).await?;
2787 ///
2788 /// # Ok(()) }
2789 /// ```
2790 pub const fn get_application_emojis(
2791 &self,
2792 application_id: Id<ApplicationMarker>,
2793 ) -> ListApplicationEmojis<'_> {
2794 ListApplicationEmojis::new(self, application_id)
2795 }
2796
2797 /// Adds an emoji to an application
2798 ///
2799 /// # Examples
2800 ///
2801 /// ```no_run
2802 /// use twilight_http::Client;
2803 /// use twilight_model::id::Id;
2804 ///
2805 /// # #[tokio::main]
2806 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
2807 /// let client = Client::new("my token".to_owned());
2808 ///
2809 /// let application_id = Id::new(1);
2810 ///
2811 /// client
2812 /// .add_application_emoji(application_id, "emoji name", "emoji image")
2813 /// .await?;
2814 ///
2815 /// # Ok(()) }
2816 /// ```
2817 pub const fn add_application_emoji<'a>(
2818 &'a self,
2819 application_id: Id<ApplicationMarker>,
2820 name: &'a str,
2821 image: &'a str,
2822 ) -> AddApplicationEmoji<'a> {
2823 AddApplicationEmoji::new(self, application_id, name, image)
2824 }
2825
2826 /// Updates an emoji associated with an application.
2827 ///
2828 /// # Examples
2829 ///
2830 /// ```no_run
2831 /// use twilight_http::Client;
2832 /// use twilight_model::id::Id;
2833 ///
2834 /// # #[tokio::main]
2835 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
2836 /// let client = Client::new("my token".to_owned());
2837 ///
2838 /// let application_id = Id::new(1);
2839 /// let emoji_id = Id::new(2);
2840 ///
2841 /// client
2842 /// .update_application_emoji(application_id, emoji_id, "new emoji name")
2843 /// .await?;
2844 ///
2845 /// # Ok(()) }
2846 /// ```
2847 pub const fn update_application_emoji<'a>(
2848 &'a self,
2849 application_id: Id<ApplicationMarker>,
2850 emoji_id: Id<EmojiMarker>,
2851 name: &'a str,
2852 ) -> UpdateApplicationEmoji<'a> {
2853 UpdateApplicationEmoji::new(self, application_id, emoji_id, name)
2854 }
2855
2856 /// Deletes an emoji associated with an application.
2857 ///
2858 /// # Examples
2859 ///
2860 /// ```no_run
2861 /// use twilight_http::Client;
2862 /// use twilight_model::id::Id;
2863 ///
2864 /// # #[tokio::main]
2865 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
2866 /// let client = Client::new("my token".to_owned());
2867 ///
2868 /// let application_id = Id::new(1);
2869 /// let emoji_id = Id::new(2);
2870 ///
2871 /// client
2872 /// .delete_application_emoji(application_id, emoji_id)
2873 /// .await?;
2874 ///
2875 /// # Ok(()) }
2876 /// ```
2877 pub const fn delete_application_emoji(
2878 &self,
2879 application_id: Id<ApplicationMarker>,
2880 emoji_id: Id<EmojiMarker>,
2881 ) -> DeleteApplicationEmoji<'_> {
2882 DeleteApplicationEmoji::new(self, application_id, emoji_id)
2883 }
2884
2885 /// Execute a request, returning a future resolving to a [`Response`].
2886 ///
2887 /// # Errors
2888 ///
2889 /// Returns an [`ErrorType::Unauthorized`] error type if the configured
2890 /// token has become invalid due to expiration, revocation, etc.
2891 ///
2892 /// [`Response`]: super::response::Response
2893 pub fn request<T>(&self, request: Request) -> ResponseFuture<T> {
2894 match self.try_request::<T>(request) {
2895 Ok(future) => future,
2896 Err(source) => ResponseFuture::error(source),
2897 }
2898 }
2899
2900 fn try_request<T>(&self, request: Request) -> Result<ResponseFuture<T>, Error> {
2901 if let Some(token_invalidated) = self.token_invalidated.as_ref() {
2902 if token_invalidated.load(Ordering::Relaxed) {
2903 return Err(Error {
2904 kind: ErrorType::Unauthorized,
2905 source: None,
2906 });
2907 }
2908 }
2909
2910 let Request {
2911 body,
2912 form,
2913 headers: req_headers,
2914 method,
2915 path,
2916 ratelimit_path,
2917 use_authorization_token,
2918 } = request;
2919
2920 let protocol = if self.use_http { "http" } else { "https" };
2921 let host = self.proxy.as_deref().unwrap_or("discord.com");
2922
2923 let url = format!("{protocol}://{host}/api/v{API_VERSION}/{path}");
2924 tracing::debug!(?url);
2925
2926 let mut builder = hyper::Request::builder().method(method.name()).uri(&url);
2927
2928 if use_authorization_token {
2929 if let Some(token) = self.token.as_deref() {
2930 let value = HeaderValue::from_str(token).map_err(|source| {
2931 let name = AUTHORIZATION.to_string();
2932
2933 Error {
2934 kind: ErrorType::CreatingHeader { name },
2935 source: Some(Box::new(source)),
2936 }
2937 })?;
2938
2939 if let Some(headers) = builder.headers_mut() {
2940 headers.insert(AUTHORIZATION, value);
2941 }
2942 }
2943 }
2944
2945 if let Some(headers) = builder.headers_mut() {
2946 if let Some(form) = &form {
2947 headers.insert(CONTENT_LENGTH, HeaderValue::from(form.len()));
2948 if let Ok(content_type) = HeaderValue::try_from(form.content_type()) {
2949 headers.insert(CONTENT_TYPE, content_type);
2950 }
2951 } else if let Some(bytes) = &body {
2952 headers.insert(CONTENT_LENGTH, HeaderValue::from(bytes.len()));
2953 headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
2954 } else if matches!(method, Method::Put | Method::Post | Method::Patch) {
2955 headers.insert(CONTENT_LENGTH, HeaderValue::from(0));
2956 }
2957
2958 #[cfg(feature = "decompression")]
2959 headers.insert(
2960 hyper::header::ACCEPT_ENCODING,
2961 HeaderValue::from_static("br"),
2962 );
2963
2964 headers.insert(USER_AGENT, HeaderValue::from_static(TWILIGHT_USER_AGENT));
2965
2966 if let Some(req_headers) = req_headers {
2967 for (maybe_name, value) in req_headers {
2968 if let Some(name) = maybe_name {
2969 headers.insert(name, value);
2970 }
2971 }
2972 }
2973
2974 if let Some(default_headers) = &self.default_headers {
2975 for (name, value) in default_headers {
2976 headers.insert(name, value.clone());
2977 }
2978 }
2979 }
2980
2981 let try_req = if let Some(form) = form {
2982 builder.body(Full::from(form.build()))
2983 } else if let Some(bytes) = body {
2984 builder.body(Full::from(bytes))
2985 } else {
2986 builder.body(Full::default())
2987 };
2988
2989 let inner = self.http.request(try_req.map_err(|source| Error {
2990 kind: ErrorType::BuildingRequest,
2991 source: Some(Box::new(source)),
2992 })?);
2993
2994 // For requests that don't use an authorization token we don't need to
2995 // remember whether the token is invalid. This may be for requests such
2996 // as webhooks and interactions.
2997 let invalid_token = use_authorization_token
2998 .then(|| self.token_invalidated.clone())
2999 .flatten();
3000
3001 Ok(if let Some(ratelimiter) = &self.ratelimiter {
3002 let tx_future = ratelimiter.wait_for_ticket(ratelimit_path);
3003
3004 ResponseFuture::ratelimit(invalid_token, inner, self.timeout, tx_future)
3005 } else {
3006 ResponseFuture::new(Box::pin(time::timeout(self.timeout, inner)), invalid_token)
3007 })
3008 }
3009}
3010
3011#[cfg(test)]
3012mod tests {
3013 use super::Client;
3014
3015 #[test]
3016 fn client_debug_with_token() {
3017 assert!(
3018 format!("{:?}", Client::new("Bot foo".to_owned())).contains("token: Some(<redacted>)")
3019 );
3020 assert!(format!("{:?}", Client::builder().build()).contains("token: None"));
3021 }
3022}