Skip to main content

fluxer/model/
mod.rs

1//! Typed structs for everything the Fluxer API returns -- users, guilds,
2//! channels, messages, embeds, and all the gateway event payloads.
3//!
4//! Most fields are `Option<T>` because the API doesn't always include
5//! everything depending on the endpoint.
6
7pub mod voice;
8use serde::{Deserialize, Serialize};
9
10/// All entity IDs in the Fluxer API are snowflake strings.
11pub type Snowflake = String;
12
13/// A Fluxer user account. Both bot and human accounts share this struct.
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct User {
16    pub id: Snowflake,
17    #[serde(default)]
18    pub username: String,
19    pub discriminator: Option<String>,
20    pub avatar: Option<String>,
21    pub banner: Option<String>,
22    #[serde(default)]
23    pub bot: Option<bool>,
24    #[serde(default)]
25    pub system: Option<bool>,
26    pub public_flags: Option<u64>,
27    pub premium: Option<u64>,
28}
29
30/// A guild (server). Full data arrives via `GUILD_CREATE`; [`UnavailableGuild`] is used before then.
31#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct Guild {
33    pub id: Snowflake,
34    pub name: Option<String>,
35    pub icon: Option<String>,
36    pub banner: Option<String>,
37    pub splash: Option<String>,
38    pub owner_id: Option<Snowflake>,
39    pub afk_channel_id: Option<Snowflake>,
40    /// AFK timeout in seconds.
41    pub afk_timeout: Option<u64>,
42    pub verification_level: Option<u64>,
43    /// 0 = all messages, 1 = only mentions.
44    pub default_message_notifications: Option<u64>,
45    pub explicit_content_filter: Option<u64>,
46    pub roles: Option<Vec<Role>>,
47    pub emojis: Option<Vec<Emoji>>,
48    pub features: Option<Vec<String>>,
49    pub member_count: Option<u64>,
50    pub max_members: Option<u64>,
51    pub description: Option<String>,
52    pub preferred_locale: Option<String>,
53    pub vanity_url_code: Option<String>,
54}
55
56/// A guild member. Wraps a [`User`] with guild-specific info like nickname and roles.
57#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct Member {
59    pub user: Option<User>,
60    pub nick: Option<String>,
61    pub avatar: Option<String>,
62    pub roles: Vec<Snowflake>,
63    pub joined_at: String,
64    pub deaf: Option<bool>,
65    pub mute: Option<bool>,
66    pub pending: Option<bool>,
67    pub permissions: Option<String>,
68    /// ISO 8601 timestamp. If set, the member is timed out until then.
69    pub communication_disabled_until: Option<String>,
70}
71
72impl Member {
73    /// Returns the member's nickname if they have one, otherwise their username.
74    pub fn display_name(&self) -> &str {
75        if let Some(nick) = &self.nick {
76            return nick.as_str();
77        }
78        self.user
79            .as_ref()
80            .map(|u| u.username.as_str())
81            .unwrap_or("")
82    }
83}
84
85/// A guild role.
86#[derive(Debug, Clone, Serialize, Deserialize)]
87pub struct Role {
88    pub id: Snowflake,
89    pub name: String,
90    /// Integer color value. 0 means no color.
91    pub color: Option<u64>,
92    /// Whether this role shows up separately in the member list.
93    pub hoist: Option<bool>,
94    pub icon: Option<String>,
95    pub position: Option<i64>,
96    /// Permission bitfield.
97    pub permissions: Option<String>,
98    /// Managed roles are created by integrations (bot roles, booster role, etc).
99    pub managed: Option<bool>,
100    pub mentionable: Option<bool>,
101}
102
103/// Custom or standard emoji. Custom emojis have both `name` and `id`,
104/// standard unicode emojis only have `name`.
105#[derive(Debug, Clone, Serialize, Deserialize)]
106pub struct Emoji {
107    pub id: Option<Snowflake>,
108    pub name: Option<String>,
109    pub roles: Option<Vec<Snowflake>>,
110    pub user: Option<User>,
111    pub require_colons: Option<bool>,
112    pub managed: Option<bool>,
113    pub animated: Option<bool>,
114    pub available: Option<bool>,
115}
116
117impl Emoji {
118    /// Formats the emoji for use in reaction endpoints. Returns `"name:id"` for
119    /// custom emojis or just the name for unicode ones.
120    pub fn to_reaction_string(&self) -> String {
121        match (&self.name, &self.id) {
122            (Some(name), Some(id)) => format!("{}:{}", name, id),
123            (Some(name), None) => name.clone(),
124            _ => String::new(),
125        }
126    }
127}
128
129/// A channel — text, voice, DM, category, etc. Check `kind` to tell them apart.
130#[derive(Debug, Clone, Serialize, Deserialize)]
131pub struct Channel {
132    pub id: Snowflake,
133    /// Channel type, see [`ChannelType`] for values.
134    #[serde(rename = "type")]
135    pub kind: Option<u8>,
136    pub guild_id: Option<Snowflake>,
137    pub position: Option<i64>,
138    pub permission_overwrites: Option<Vec<PermissionOverwrite>>,
139    pub name: Option<String>,
140    pub topic: Option<String>,
141    pub nsfw: Option<bool>,
142    pub last_message_id: Option<Snowflake>,
143    /// Bits per second, for voice channels.
144    pub bitrate: Option<u64>,
145    /// 0 = unlimited.
146    pub user_limit: Option<u64>,
147    /// Slowmode, in seconds.
148    pub rate_limit_per_user: Option<u64>,
149    /// Recipients for DM/group DM channels.
150    pub recipients: Option<Vec<User>>,
151    pub icon: Option<String>,
152    pub owner_id: Option<Snowflake>,
153    pub parent_id: Option<Snowflake>,
154    pub last_pin_timestamp: Option<String>,
155}
156
157/// Numeric channel type values that map to [`Channel::kind`].
158#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
159#[repr(u8)]
160pub enum ChannelType {
161    Text = 0,
162    Dm = 1,
163    Voice = 2,
164    GroupDm = 3,
165    Category = 4,
166    Announcement = 5,
167    Stage = 13,
168}
169
170/// Permission overwrite for a channel. `kind` is 0 for role, 1 for member.
171#[derive(Debug, Clone, Serialize, Deserialize)]
172pub struct PermissionOverwrite {
173    pub id: Snowflake,
174    #[serde(rename = "type")]
175    pub kind: u8,
176    pub allow: Option<String>,
177    pub deny: Option<String>,
178}
179
180/// A message sent in a channel.
181#[derive(Debug, Clone, Serialize, Deserialize)]
182pub struct Message {
183    pub id: Snowflake,
184    pub channel_id: Option<Snowflake>,
185    pub guild_id: Option<Snowflake>,
186    pub author: User,
187    /// Only present in guild messages.
188    pub member: Option<Member>,
189    pub content: Option<String>,
190    pub timestamp: Option<String>,
191    pub edited_timestamp: Option<String>,
192    pub tts: Option<bool>,
193    pub mention_everyone: Option<bool>,
194    pub mentions: Option<Vec<User>>,
195    pub mention_roles: Option<Vec<Snowflake>>,
196    pub attachments: Option<Vec<Attachment>>,
197    pub embeds: Option<Vec<Embed>>,
198    pub reactions: Option<Vec<Reaction>>,
199    pub pinned: Option<bool>,
200    pub webhook_id: Option<Snowflake>,
201    /// 0 = default, 19 = reply, etc.
202    #[serde(rename = "type")]
203    pub kind: Option<u8>,
204    pub referenced_message: Option<Box<Message>>,
205    pub flags: Option<u64>,
206    pub stickers: Option<Vec<serde_json::Value>>,
207}
208
209#[derive(Debug, Clone, Serialize, Deserialize)]
210pub struct PinnedMessage {
211    pub message: Message,
212    pub pinned_at: Option<String>,
213}
214
215#[derive(Debug, Clone, Serialize, Deserialize)]
216pub struct PinsResponse {
217    pub items: Vec<PinnedMessage>,
218    pub has_more: Option<bool>,
219}
220
221/// A file attached to a message.
222#[derive(Debug, Clone, Serialize, Deserialize)]
223pub struct Attachment {
224    pub id: Snowflake,
225    pub filename: Option<String>,
226    pub description: Option<String>,
227    pub content_type: Option<String>,
228    pub size: Option<u64>,
229    pub url: Option<String>,
230    pub proxy_url: Option<String>,
231    pub height: Option<u64>,
232    pub width: Option<u64>,
233    pub ephemeral: Option<bool>,
234}
235
236/// Rich embed. Use [`EmbedBuilder`] to construct these.
237#[derive(Debug, Clone, Serialize, Deserialize, Default)]
238pub struct Embed {
239    pub title: Option<String>,
240    #[serde(rename = "type")]
241    pub kind: Option<String>,
242    pub description: Option<String>,
243    pub url: Option<String>,
244    pub timestamp: Option<String>,
245    /// Sidebar color as an integer, e.g. `0xFF0000` for red.
246    pub color: Option<u64>,
247    pub footer: Option<EmbedFooter>,
248    pub image: Option<EmbedMedia>,
249    pub thumbnail: Option<EmbedMedia>,
250    pub video: Option<EmbedMedia>,
251    pub author: Option<EmbedAuthor>,
252    pub fields: Option<Vec<EmbedField>>,
253}
254
255#[derive(Debug, Clone, Serialize, Deserialize)]
256pub struct EmbedFooter {
257    pub text: String,
258    pub icon_url: Option<String>,
259}
260
261#[derive(Debug, Clone, Serialize, Deserialize)]
262pub struct EmbedMedia {
263    pub url: String,
264    pub height: Option<u64>,
265    pub width: Option<u64>,
266}
267
268#[derive(Debug, Clone, Serialize, Deserialize)]
269pub struct EmbedAuthor {
270    pub name: String,
271    pub url: Option<String>,
272    pub icon_url: Option<String>,
273}
274
275#[derive(Debug, Clone, Serialize, Deserialize)]
276pub struct EmbedField {
277    pub name: String,
278    pub value: String,
279    /// If true, fields can sit side-by-side.
280    #[serde(default)]
281    pub inline: bool,
282}
283
284#[derive(Debug, Clone, Serialize, Deserialize)]
285pub struct Reaction {
286    pub count: u64,
287    pub me: bool,
288    pub emoji: Emoji,
289}
290
291/// Builder for [`Embed`]. Chain methods and call `.build()` at the end.
292///
293/// ```rust
294/// use fluxer::prelude::*;
295///
296/// let embed = EmbedBuilder::new()
297///     .title("Hello")
298///     .description("World")
299///     .color(0x00FF00)
300///     .build();
301/// ```
302#[derive(Debug, Default)]
303pub struct EmbedBuilder(Embed);
304
305impl EmbedBuilder {
306    pub fn new() -> Self {
307        Self::default()
308    }
309
310    pub fn title(mut self, title: impl Into<String>) -> Self {
311        self.0.title = Some(title.into());
312        self
313    }
314    pub fn description(mut self, desc: impl Into<String>) -> Self {
315        self.0.description = Some(desc.into());
316        self
317    }
318    pub fn url(mut self, url: impl Into<String>) -> Self {
319        self.0.url = Some(url.into());
320        self
321    }
322    pub fn color(mut self, color: u64) -> Self {
323        self.0.color = Some(color);
324        self
325    }
326    pub fn timestamp(mut self, ts: impl Into<String>) -> Self {
327        self.0.timestamp = Some(ts.into());
328        self
329    }
330    pub fn footer(mut self, text: impl Into<String>, icon_url: Option<String>) -> Self {
331        self.0.footer = Some(EmbedFooter { text: text.into(), icon_url });
332        self
333    }
334    pub fn image(mut self, url: impl Into<String>) -> Self {
335        self.0.image = Some(EmbedMedia { url: url.into(), height: None, width: None });
336        self
337    }
338    pub fn thumbnail(mut self, url: impl Into<String>) -> Self {
339        self.0.thumbnail = Some(EmbedMedia { url: url.into(), height: None, width: None });
340        self
341    }
342    pub fn author(mut self, name: impl Into<String>, url: Option<String>, icon_url: Option<String>) -> Self {
343        self.0.author = Some(EmbedAuthor { name: name.into(), url, icon_url });
344        self
345    }
346    pub fn field(mut self, name: impl Into<String>, value: impl Into<String>, inline: bool) -> Self {
347        let fields = self.0.fields.get_or_insert_with(Vec::new);
348        fields.push(EmbedField { name: name.into(), value: value.into(), inline });
349        self
350    }
351    pub fn build(self) -> Embed {
352        self.0
353    }
354}
355
356#[derive(Debug, Clone, Serialize, Deserialize)]
357pub struct Invite {
358    pub code: String,
359    pub guild: Option<PartialGuild>,
360    pub channel: Option<PartialChannel>,
361    pub inviter: Option<User>,
362    pub target_user: Option<User>,
363    pub approximate_member_count: Option<u64>,
364    pub expires_at: Option<String>,
365}
366
367#[derive(Debug, Clone, Serialize, Deserialize)]
368pub struct PartialGuild {
369    pub id: Snowflake,
370    pub name: String,
371    pub icon: Option<String>,
372    pub splash: Option<String>,
373    pub banner: Option<String>,
374}
375
376#[derive(Debug, Clone, Serialize, Deserialize)]
377pub struct PartialChannel {
378    pub id: Snowflake,
379    pub name: Option<String>,
380    #[serde(rename = "type")]
381    pub kind: Option<u8>,
382}
383
384/// A webhook. Use [`Http::execute_webhook`](crate::http::Http::execute_webhook) to post through one.
385#[derive(Debug, Clone, Serialize, Deserialize)]
386pub struct Webhook {
387    pub id: Snowflake,
388    #[serde(rename = "type")]
389    pub kind: Option<u8>,
390    pub guild_id: Option<Snowflake>,
391    pub channel_id: Option<Snowflake>,
392    pub user: Option<User>,
393    pub name: Option<String>,
394    pub avatar: Option<String>,
395    pub token: Option<String>,
396    pub url: Option<String>,
397}
398
399// --- Gateway event payloads ---
400
401#[derive(Debug, Clone, Serialize, Deserialize)]
402pub struct TypingStart {
403    pub channel_id: Option<Snowflake>,
404    pub guild_id: Option<Snowflake>,
405    pub user_id: Snowflake,
406    /// Unix timestamp in seconds.
407    pub timestamp: u64,
408    pub member: Option<Member>,
409}
410
411#[derive(Debug, Clone, Serialize, Deserialize)]
412pub struct ReactionAdd {
413    pub user_id: Snowflake,
414    pub channel_id: Option<Snowflake>,
415    pub message_id: Snowflake,
416    pub guild_id: Option<Snowflake>,
417    pub member: Option<Member>,
418    pub emoji: Emoji,
419}
420
421#[derive(Debug, Clone, Serialize, Deserialize)]
422pub struct ReactionRemove {
423    pub user_id: Snowflake,
424    pub channel_id: Option<Snowflake>,
425    pub message_id: Snowflake,
426    pub guild_id: Option<Snowflake>,
427    pub emoji: Emoji,
428}
429
430#[derive(Debug, Clone, Serialize, Deserialize)]
431pub struct ReactionRemoveAll {
432    pub channel_id: Option<Snowflake>,
433    pub message_id: Snowflake,
434    pub guild_id: Option<Snowflake>,
435}
436
437#[derive(Debug, Clone, Serialize, Deserialize)]
438pub struct ReactionRemoveEmoji {
439    pub channel_id: Option<Snowflake>,
440    pub guild_id: Option<Snowflake>,
441    pub message_id: Snowflake,
442    pub emoji: Emoji,
443}
444
445/// Partial message data from an edit. Only changed fields are populated.
446#[derive(Debug, Clone, Serialize, Deserialize)]
447pub struct MessageUpdate {
448    pub id: Snowflake,
449    pub channel_id: Option<Snowflake>,
450    pub guild_id: Option<Snowflake>,
451    pub author: Option<User>,
452    pub content: Option<String>,
453    pub edited_timestamp: Option<String>,
454    pub embeds: Option<Vec<Embed>>,
455    pub attachments: Option<Vec<Attachment>>,
456    pub pinned: Option<bool>,
457    pub flags: Option<u64>,
458}
459
460#[derive(Debug, Clone, Serialize, Deserialize)]
461pub struct MessageDelete {
462    pub id: Snowflake,
463    pub channel_id: Option<Snowflake>,
464    pub guild_id: Option<Snowflake>,
465}
466
467#[derive(Debug, Clone, Serialize, Deserialize)]
468pub struct MessageDeleteBulk {
469    pub ids: Vec<Snowflake>,
470    pub channel_id: Option<Snowflake>,
471    pub guild_id: Option<Snowflake>,
472}
473
474#[derive(Debug, Clone, Serialize, Deserialize)]
475pub struct GuildMemberAdd {
476    pub guild_id: Snowflake,
477    #[serde(flatten)]
478    pub member: Member,
479}
480
481#[derive(Debug, Clone, Serialize, Deserialize)]
482pub struct GuildMemberRemove {
483    pub guild_id: Snowflake,
484    pub user: User,
485}
486
487#[derive(Debug, Clone, Serialize, Deserialize)]
488pub struct GuildMemberUpdate {
489    pub guild_id: Snowflake,
490    pub roles: Vec<Snowflake>,
491    pub user: User,
492    pub nick: Option<String>,
493    pub joined_at: Option<String>,
494    pub pending: Option<bool>,
495    pub communication_disabled_until: Option<String>,
496}
497
498#[derive(Debug, Clone, Serialize, Deserialize)]
499pub struct Ban {
500    pub reason: Option<String>,
501    pub user: User,
502}
503
504#[derive(Debug, Clone, Serialize, Deserialize)]
505pub struct GuildBanAdd {
506    pub guild_id: Snowflake,
507    pub user: User,
508}
509
510#[derive(Debug, Clone, Serialize, Deserialize)]
511pub struct GuildBanRemove {
512    pub guild_id: Snowflake,
513    pub user: User,
514}
515
516#[derive(Debug, Clone, Serialize, Deserialize)]
517pub struct GuildRoleCreate {
518    pub guild_id: Snowflake,
519    pub role: Role,
520}
521
522#[derive(Debug, Clone, Serialize, Deserialize)]
523pub struct GuildRoleUpdate {
524    pub guild_id: Snowflake,
525    pub role: Role,
526}
527
528#[derive(Debug, Clone, Serialize, Deserialize)]
529pub struct GuildRoleDelete {
530    pub guild_id: Snowflake,
531    pub role_id: Snowflake,
532}
533
534#[derive(Debug, Clone, Serialize, Deserialize)]
535pub struct ChannelDelete {
536    pub id: Snowflake,
537    #[serde(rename = "type")]
538    pub kind: Option<u8>,
539    pub guild_id: Option<Snowflake>,
540}
541
542#[derive(Debug, Clone, Serialize, Deserialize)]
543pub struct ChannelPinsUpdate {
544    pub guild_id: Option<Snowflake>,
545    pub channel_id: Option<Snowflake>,
546    pub last_pin_timestamp: Option<String>,
547}
548
549/// Received once after connecting. Contains the bot user, session info for
550/// resuming, and the initial guild list.
551#[derive(Debug, Clone, Serialize, Deserialize)]
552pub struct Ready {
553    pub v: Option<u64>,
554    pub session_id: String,
555    pub resume_gateway_url: Option<String>,
556    pub user: User,
557    /// Guilds come in as unavailable first; full data arrives via GUILD_CREATE events.
558    pub guilds: Option<Vec<UnavailableGuild>>,
559    /// `[shard_id, num_shards]`
560    pub shard: Option<[u64; 2]>,
561}
562
563#[derive(Debug, Clone, Serialize, Deserialize)]
564pub struct UnavailableGuild {
565    pub id: Snowflake,
566    /// `true` = temporary outage, `false`/absent = bot was removed.
567    pub unavailable: Option<bool>,
568}
569
570#[derive(Debug, Deserialize)]
571pub struct GatewayBotResponse {
572    pub url: String,
573}
574
575#[derive(Debug, Clone, Serialize, Deserialize)]
576pub struct GuildEmojisUpdate {
577    pub guild_id: Snowflake,
578    pub emojis: Vec<serde_json::Value>,
579}
580
581#[derive(Debug, Clone, Serialize, Deserialize)]
582pub struct GuildStickersUpdate {
583    pub guild_id: Snowflake,
584    pub stickers: Vec<serde_json::Value>,
585}
586
587#[derive(Debug, Clone, Serialize, Deserialize)]
588pub struct GuildRoleUpdateBulk {
589    pub guild_id: Snowflake,
590    pub roles: Vec<serde_json::Value>,
591}
592
593#[derive(Debug, Clone, Serialize, Deserialize)]
594pub struct ChannelUpdateBulk {
595    pub guild_id: Option<Snowflake>,
596    pub channels: Vec<serde_json::Value>,
597}
598
599#[derive(Debug, Clone, Serialize, Deserialize)]
600pub struct InviteCreate {
601    pub channel_id: Option<Snowflake>,
602    pub guild_id: Option<Snowflake>,
603    pub code: Option<String>,
604}
605
606#[derive(Debug, Clone, Serialize, Deserialize)]
607pub struct InviteDelete {
608    pub channel_id: Option<Snowflake>,
609    pub guild_id: Option<Snowflake>,
610    pub code: String,
611}
612
613#[derive(Debug, Clone, Serialize, Deserialize)]
614pub struct WebhooksUpdate {
615    pub channel_id: Snowflake,
616    pub guild_id: Option<Snowflake>,
617}
618
619// --- Request payloads ---
620
621/// Payload for sending/editing messages. All fields optional; only set what you need.
622#[derive(Debug, Clone, Serialize, Default)]
623pub struct MessageCreatePayload {
624    #[serde(skip_serializing_if = "Option::is_none")]
625    pub content: Option<String>,
626    #[serde(skip_serializing_if = "Option::is_none")]
627    pub tts: Option<bool>,
628    #[serde(skip_serializing_if = "Option::is_none")]
629    pub embeds: Option<Vec<Embed>>,
630    #[serde(skip_serializing_if = "Option::is_none")]
631    pub flags: Option<u64>,
632    #[serde(skip_serializing_if = "Option::is_none")]
633    pub message_reference: Option<MessageReference>,
634    #[serde(skip_serializing_if = "Option::is_none")]
635    pub referenced_message_id: Option<Snowflake>,
636}
637
638#[derive(Debug, Clone, Serialize)]
639pub struct MessageReference {
640    pub message_id: Snowflake,
641    pub channel_id: Option<Snowflake>,
642    pub guild_id: Option<Snowflake>,
643    #[serde(skip_serializing_if = "Option::is_none")]
644    pub fail_if_not_exists: Option<bool>,
645}
646
647#[derive(Debug, Clone, Serialize, Default)]
648pub struct ChannelCreatePayload {
649    pub name: String,
650    #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
651    pub kind: Option<u8>,
652    #[serde(skip_serializing_if = "Option::is_none")]
653    pub topic: Option<String>,
654    #[serde(skip_serializing_if = "Option::is_none")]
655    pub bitrate: Option<u64>,
656    #[serde(skip_serializing_if = "Option::is_none")]
657    pub user_limit: Option<u64>,
658    #[serde(skip_serializing_if = "Option::is_none")]
659    pub rate_limit_per_user: Option<u64>,
660    #[serde(skip_serializing_if = "Option::is_none")]
661    pub position: Option<i64>,
662    #[serde(skip_serializing_if = "Option::is_none")]
663    pub parent_id: Option<Snowflake>,
664    #[serde(skip_serializing_if = "Option::is_none")]
665    pub nsfw: Option<bool>,
666}
667
668/// For nullable fields like `nick`, use `Some(None)` to clear them.
669#[derive(Debug, Clone, Serialize, Default)]
670pub struct EditMemberPayload {
671    #[serde(skip_serializing_if = "Option::is_none")]
672    pub nick: Option<Option<String>>,
673    #[serde(skip_serializing_if = "Option::is_none")]
674    pub roles: Option<Vec<Snowflake>>,
675    #[serde(skip_serializing_if = "Option::is_none")]
676    pub mute: Option<bool>,
677    #[serde(skip_serializing_if = "Option::is_none")]
678    pub deaf: Option<bool>,
679    #[serde(skip_serializing_if = "Option::is_none")]
680    pub channel_id: Option<Option<Snowflake>>,
681    #[serde(skip_serializing_if = "Option::is_none")]
682    pub communication_disabled_until: Option<Option<String>>,
683}
684
685#[derive(Debug, Clone, Serialize, Default)]
686pub struct CreateRolePayload {
687    pub name: String,
688    #[serde(skip_serializing_if = "Option::is_none")]
689    pub permissions: Option<String>,
690    #[serde(skip_serializing_if = "Option::is_none")]
691    pub color: Option<u64>,
692    #[serde(skip_serializing_if = "Option::is_none")]
693    pub hoist: Option<bool>,
694    #[serde(skip_serializing_if = "Option::is_none")]
695    pub mentionable: Option<bool>,
696}
697
698#[derive(Debug, Clone, Serialize, Default)]
699pub struct EditRolePayload {
700    #[serde(skip_serializing_if = "Option::is_none")]
701    pub name: Option<String>,
702    #[serde(skip_serializing_if = "Option::is_none")]
703    pub permissions: Option<String>,
704    #[serde(skip_serializing_if = "Option::is_none")]
705    pub color: Option<u64>,
706    #[serde(skip_serializing_if = "Option::is_none")]
707    pub hoist: Option<bool>,
708    #[serde(skip_serializing_if = "Option::is_none")]
709    pub mentionable: Option<bool>,
710}
711
712#[derive(Debug, Clone, Serialize, Default)]
713pub struct CreateInvitePayload {
714    /// Seconds. 0 = never expires.
715    #[serde(skip_serializing_if = "Option::is_none")]
716    pub max_age: Option<u64>,
717    /// 0 = unlimited.
718    #[serde(skip_serializing_if = "Option::is_none")]
719    pub max_uses: Option<u64>,
720    /// If true, members joined via this invite get kicked when they disconnect
721    /// (unless they've been given a role).
722    #[serde(skip_serializing_if = "Option::is_none")]
723    pub temporary: Option<bool>,
724    #[serde(skip_serializing_if = "Option::is_none")]
725    pub unique: Option<bool>,
726}
727
728/// Query params for fetching messages. Only set one of `before`/`after`/`around`.
729#[derive(Debug, Clone, Default)]
730pub struct GetMessagesQuery {
731    /// 1-100.
732    pub limit: Option<u8>,
733    pub before: Option<Snowflake>,
734    pub after: Option<Snowflake>,
735    pub around: Option<Snowflake>,
736}
737
738impl GetMessagesQuery {
739    pub fn to_query_string(&self) -> String {
740        let mut parts = Vec::new();
741        if let Some(l) = self.limit {
742            parts.push(format!("limit={}", l.min(100)));
743        }
744        if let Some(ref b) = self.before {
745            parts.push(format!("before={}", b));
746        }
747        if let Some(ref a) = self.after {
748            parts.push(format!("after={}", a));
749        }
750        if let Some(ref ar) = self.around {
751            parts.push(format!("around={}", ar));
752        }
753        if parts.is_empty() {
754            String::new()
755        } else {
756            format!("?{}", parts.join("&"))
757        }
758    }
759}
760
761#[derive(Debug, Clone, Serialize, Default)]
762pub struct EditGuildPayload {
763    #[serde(skip_serializing_if = "Option::is_none")]
764    pub name: Option<String>,
765    #[serde(skip_serializing_if = "Option::is_none")]
766    pub description: Option<String>,
767    #[serde(skip_serializing_if = "Option::is_none")]
768    pub preferred_locale: Option<String>,
769    #[serde(skip_serializing_if = "Option::is_none")]
770    pub afk_channel_id: Option<Option<Snowflake>>,
771    #[serde(skip_serializing_if = "Option::is_none")]
772    pub afk_timeout: Option<u64>,
773    #[serde(skip_serializing_if = "Option::is_none")]
774    pub verification_level: Option<u64>,
775    #[serde(skip_serializing_if = "Option::is_none")]
776    pub default_message_notifications: Option<u64>,
777    #[serde(skip_serializing_if = "Option::is_none")]
778    pub explicit_content_filter: Option<u64>,
779}
780
781#[derive(Debug, Clone, Serialize, Default)]
782pub struct WebhookExecutePayload {
783    #[serde(skip_serializing_if = "Option::is_none")]
784    pub content: Option<String>,
785    /// Override the webhook's name for this message.
786    #[serde(skip_serializing_if = "Option::is_none")]
787    pub username: Option<String>,
788    /// Override the webhook's avatar for this message.
789    #[serde(skip_serializing_if = "Option::is_none")]
790    pub avatar_url: Option<String>,
791    #[serde(skip_serializing_if = "Option::is_none")]
792    pub tts: Option<bool>,
793    #[serde(skip_serializing_if = "Option::is_none")]
794    pub embeds: Option<Vec<Embed>>,
795}