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