1use std::mem::transmute;
4
5use serde::ser::{Serialize, Serializer};
6
7mod change;
8mod utils;
9
10pub use change::{AffectedRole, Change, EntityType};
11use utils::{optional_string, users, webhooks};
12
13use crate::model::prelude::*;
14
15#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
19#[derive(Clone, Copy, Debug)]
20#[non_exhaustive]
21pub enum Action {
22 GuildUpdate,
23 Channel(ChannelAction),
24 ChannelOverwrite(ChannelOverwriteAction),
25 Member(MemberAction),
26 Role(RoleAction),
27 Invite(InviteAction),
28 Webhook(WebhookAction),
29 Emoji(EmojiAction),
30 Message(MessageAction),
31 Integration(IntegrationAction),
32 StageInstance(StageInstanceAction),
33 Sticker(StickerAction),
34 ScheduledEvent(ScheduledEventAction),
35 Thread(ThreadAction),
36 AutoMod(AutoModAction),
37 CreatorMonetization(CreatorMonetizationAction),
38 VoiceChannelStatus(VoiceChannelStatusAction),
39 Unknown(u8),
40}
41
42impl Action {
43 #[must_use]
44 pub const fn num(self) -> u8 {
45 match self {
46 Self::GuildUpdate => 1,
47 Self::Channel(x) => x as u8,
48 Self::ChannelOverwrite(x) => x as u8,
49 Self::Member(x) => x as u8,
50 Self::Role(x) => x as u8,
51 Self::Invite(x) => x as u8,
52 Self::Webhook(x) => x as u8,
53 Self::Emoji(x) => x as u8,
54 Self::Message(x) => x as u8,
55 Self::Integration(x) => x as u8,
56 Self::StageInstance(x) => x as u8,
57 Self::Sticker(x) => x as u8,
58 Self::ScheduledEvent(x) => x as u8,
59 Self::Thread(x) => x as u8,
60 Self::AutoMod(x) => x as u8,
61 Self::CreatorMonetization(x) => x as u8,
62 Self::VoiceChannelStatus(x) => x as u8,
63 Self::Unknown(x) => x,
64 }
65 }
66
67 #[must_use]
68 #[allow(unknown_lints, clippy::missing_transmute_annotations)]
69 pub fn from_value(value: u8) -> Action {
70 match value {
71 1 => Action::GuildUpdate,
72 10..=12 => Action::Channel(unsafe { transmute(value) }),
73 13..=15 => Action::ChannelOverwrite(unsafe { transmute(value) }),
74 20..=28 => Action::Member(unsafe { transmute(value) }),
75 30..=32 => Action::Role(unsafe { transmute(value) }),
76 40..=42 => Action::Invite(unsafe { transmute(value) }),
77 50..=52 => Action::Webhook(unsafe { transmute(value) }),
78 60..=62 => Action::Emoji(unsafe { transmute(value) }),
79 72..=75 => Action::Message(unsafe { transmute(value) }),
80 80..=82 => Action::Integration(unsafe { transmute(value) }),
81 83..=85 => Action::StageInstance(unsafe { transmute(value) }),
82 90..=92 => Action::Sticker(unsafe { transmute(value) }),
83 100..=102 => Action::ScheduledEvent(unsafe { transmute(value) }),
84 110..=112 => Action::Thread(unsafe { transmute(value) }),
85 140..=145 => Action::AutoMod(unsafe { transmute(value) }),
86 150..=151 => Action::CreatorMonetization(unsafe { transmute(value) }),
87 192..=193 => Action::VoiceChannelStatus(unsafe { transmute(value) }),
88 _ => Action::Unknown(value),
89 }
90 }
91}
92
93impl<'de> Deserialize<'de> for Action {
95 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
96 let value = u8::deserialize(deserializer)?;
97 Ok(Action::from_value(value))
98 }
99}
100
101impl Serialize for Action {
102 fn serialize<S: Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> {
103 serializer.serialize_u8(self.num())
104 }
105}
106
107#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
109#[derive(Clone, Copy, Debug)]
110#[non_exhaustive]
111#[repr(u8)]
112pub enum ChannelAction {
113 Create = 10,
114 Update = 11,
115 Delete = 12,
116}
117
118#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
120#[derive(Clone, Copy, Debug)]
121#[non_exhaustive]
122#[repr(u8)]
123pub enum ChannelOverwriteAction {
124 Create = 13,
125 Update = 14,
126 Delete = 15,
127}
128
129#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
131#[derive(Clone, Copy, Debug)]
132#[non_exhaustive]
133#[repr(u8)]
134pub enum MemberAction {
135 Kick = 20,
136 Prune = 21,
137 BanAdd = 22,
138 BanRemove = 23,
139 Update = 24,
140 RoleUpdate = 25,
141 MemberMove = 26,
142 MemberDisconnect = 27,
143 BotAdd = 28,
144}
145
146#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
148#[derive(Clone, Copy, Debug)]
149#[non_exhaustive]
150#[repr(u8)]
151pub enum RoleAction {
152 Create = 30,
153 Update = 31,
154 Delete = 32,
155}
156
157#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
159#[derive(Clone, Copy, Debug)]
160#[non_exhaustive]
161#[repr(u8)]
162pub enum InviteAction {
163 Create = 40,
164 Update = 41,
165 Delete = 42,
166}
167
168#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
170#[derive(Clone, Copy, Debug)]
171#[non_exhaustive]
172#[repr(u8)]
173pub enum WebhookAction {
174 Create = 50,
175 Update = 51,
176 Delete = 52,
177}
178
179#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
181#[derive(Clone, Copy, Debug)]
182#[non_exhaustive]
183#[repr(u8)]
184pub enum EmojiAction {
185 Create = 60,
186 Update = 61,
187 Delete = 62,
188}
189
190#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
192#[derive(Clone, Copy, Debug)]
193#[non_exhaustive]
194#[repr(u8)]
195pub enum MessageAction {
196 Delete = 72,
197 BulkDelete = 73,
198 Pin = 74,
199 Unpin = 75,
200}
201
202#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
204#[derive(Clone, Copy, Debug)]
205#[non_exhaustive]
206#[repr(u8)]
207pub enum IntegrationAction {
208 Create = 80,
209 Update = 81,
210 Delete = 82,
211}
212
213#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
215#[derive(Clone, Copy, Debug)]
216#[non_exhaustive]
217#[repr(u8)]
218pub enum StageInstanceAction {
219 Create = 83,
220 Update = 84,
221 Delete = 85,
222}
223
224#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
226#[derive(Clone, Copy, Debug)]
227#[non_exhaustive]
228#[repr(u8)]
229pub enum StickerAction {
230 Create = 90,
231 Update = 91,
232 Delete = 92,
233}
234
235#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
237#[derive(Clone, Copy, Debug)]
238#[non_exhaustive]
239#[repr(u8)]
240pub enum ScheduledEventAction {
241 Create = 100,
242 Update = 101,
243 Delete = 102,
244}
245
246#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
248#[derive(Clone, Copy, Debug)]
249#[non_exhaustive]
250#[repr(u8)]
251pub enum ThreadAction {
252 Create = 110,
253 Update = 111,
254 Delete = 112,
255}
256
257#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
259#[derive(Copy, Clone, Debug)]
260#[non_exhaustive]
261#[repr(u8)]
262pub enum AutoModAction {
263 RuleCreate = 140,
264 RuleUpdate = 141,
265 RuleDelete = 142,
266 BlockMessage = 143,
267 FlagToChannel = 144,
268 UserCommunicationDisabled = 145,
269}
270
271#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
273#[derive(Copy, Clone, Debug)]
274#[non_exhaustive]
275#[repr(u8)]
276pub enum CreatorMonetizationAction {
277 RequestCreated = 150,
278 TermsAccepted = 151,
279}
280
281#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
283#[derive(Copy, Clone, Debug)]
284#[non_exhaustive]
285#[repr(u8)]
286pub enum VoiceChannelStatusAction {
287 StatusUpdate = 192,
288 StatusDelete = 193,
289}
290
291#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
293#[derive(Debug, Deserialize, Serialize)]
294#[non_exhaustive]
295pub struct AuditLogs {
296 #[serde(rename = "audit_log_entries")]
298 pub entries: Vec<AuditLogEntry>,
299 pub auto_moderation_rules: Vec<Rule>,
301 pub application_commands: Vec<Command>,
303 pub guild_scheduled_events: Vec<ScheduledEvent>,
305 pub integrations: Vec<PartialIntegration>,
307 pub threads: Vec<GuildChannel>,
312 #[serde(with = "users")]
314 pub users: HashMap<UserId, User>,
315 #[serde(with = "webhooks")]
317 pub webhooks: HashMap<WebhookId, Webhook>,
318}
319
320#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
324#[derive(Clone, Debug, Deserialize, Serialize)]
325#[non_exhaustive]
326pub struct PartialIntegration {
327 pub id: IntegrationId,
328 pub name: String,
329 #[serde(rename = "type")]
330 pub kind: String,
331 pub account: IntegrationAccount,
332 pub application: Option<IntegrationApplication>,
333}
334
335#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
337#[derive(Debug, Deserialize, Serialize, Clone)]
338#[non_exhaustive]
339pub struct AuditLogEntry {
340 pub target_id: Option<GenericId>,
342 #[serde(rename = "action_type")]
344 pub action: Action,
345 pub reason: Option<String>,
347 pub user_id: UserId,
349 pub changes: Option<Vec<Change>>,
351 pub id: AuditLogEntryId,
353 pub options: Option<Options>,
355}
356
357#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
360#[derive(Debug, Deserialize, Serialize, Clone)]
361#[non_exhaustive]
362pub struct Options {
363 pub auto_moderation_rule_name: Option<String>,
365 pub auto_moderation_rule_trigger_type: Option<String>,
367 pub application_id: Option<ApplicationId>,
369 #[serde(default, with = "optional_string")]
371 pub delete_member_days: Option<u64>,
372 #[serde(default, with = "optional_string")]
374 pub members_removed: Option<u64>,
375 #[serde(default)]
377 pub channel_id: Option<ChannelId>,
378 #[serde(default, with = "optional_string")]
380 pub count: Option<u64>,
381 #[serde(default)]
383 pub id: Option<GenericId>,
384 #[serde(default, rename = "type")]
386 pub kind: Option<String>,
387 #[serde(default)]
389 pub message_id: Option<MessageId>,
390 #[serde(default)]
392 pub role_name: Option<String>,
393 #[serde(default)]
395 pub status: Option<String>,
396}
397
398#[cfg(test)]
399mod tests {
400 use super::*;
401
402 #[test]
403 fn action_value() {
404 macro_rules! assert_action {
405 ($action:pat, $num:literal) => {{
406 let a = Action::from_value($num);
407 assert!(matches!(a, $action), "{:?} didn't match the variant", a);
408 assert_eq!(a.num(), $num);
409 }};
410 }
411
412 assert_action!(Action::GuildUpdate, 1);
413 assert_action!(Action::Channel(ChannelAction::Create), 10);
414 assert_action!(Action::Channel(ChannelAction::Update), 11);
415 assert_action!(Action::Channel(ChannelAction::Delete), 12);
416 assert_action!(Action::ChannelOverwrite(ChannelOverwriteAction::Create), 13);
417 assert_action!(Action::ChannelOverwrite(ChannelOverwriteAction::Update), 14);
418 assert_action!(Action::ChannelOverwrite(ChannelOverwriteAction::Delete), 15);
419 assert_action!(Action::Member(MemberAction::Kick), 20);
420 assert_action!(Action::Member(MemberAction::Prune), 21);
421 assert_action!(Action::Member(MemberAction::BanAdd), 22);
422 assert_action!(Action::Member(MemberAction::BanRemove), 23);
423 assert_action!(Action::Member(MemberAction::Update), 24);
424 assert_action!(Action::Member(MemberAction::RoleUpdate), 25);
425 assert_action!(Action::Member(MemberAction::MemberMove), 26);
426 assert_action!(Action::Member(MemberAction::MemberDisconnect), 27);
427 assert_action!(Action::Member(MemberAction::BotAdd), 28);
428 assert_action!(Action::Role(RoleAction::Create), 30);
429 assert_action!(Action::Role(RoleAction::Update), 31);
430 assert_action!(Action::Role(RoleAction::Delete), 32);
431 assert_action!(Action::Invite(InviteAction::Create), 40);
432 assert_action!(Action::Invite(InviteAction::Update), 41);
433 assert_action!(Action::Invite(InviteAction::Delete), 42);
434 assert_action!(Action::Webhook(WebhookAction::Create), 50);
435 assert_action!(Action::Webhook(WebhookAction::Update), 51);
436 assert_action!(Action::Webhook(WebhookAction::Delete), 52);
437 assert_action!(Action::Emoji(EmojiAction::Create), 60);
438 assert_action!(Action::Emoji(EmojiAction::Update), 61);
439 assert_action!(Action::Emoji(EmojiAction::Delete), 62);
440 assert_action!(Action::Message(MessageAction::Delete), 72);
441 assert_action!(Action::Message(MessageAction::BulkDelete), 73);
442 assert_action!(Action::Message(MessageAction::Pin), 74);
443 assert_action!(Action::Message(MessageAction::Unpin), 75);
444 assert_action!(Action::Integration(IntegrationAction::Create), 80);
445 assert_action!(Action::Integration(IntegrationAction::Update), 81);
446 assert_action!(Action::Integration(IntegrationAction::Delete), 82);
447 assert_action!(Action::StageInstance(StageInstanceAction::Create), 83);
448 assert_action!(Action::StageInstance(StageInstanceAction::Update), 84);
449 assert_action!(Action::StageInstance(StageInstanceAction::Delete), 85);
450 assert_action!(Action::Sticker(StickerAction::Create), 90);
451 assert_action!(Action::Sticker(StickerAction::Update), 91);
452 assert_action!(Action::Sticker(StickerAction::Delete), 92);
453 assert_action!(Action::ScheduledEvent(ScheduledEventAction::Create), 100);
454 assert_action!(Action::ScheduledEvent(ScheduledEventAction::Update), 101);
455 assert_action!(Action::ScheduledEvent(ScheduledEventAction::Delete), 102);
456 assert_action!(Action::Thread(ThreadAction::Create), 110);
457 assert_action!(Action::Thread(ThreadAction::Update), 111);
458 assert_action!(Action::Thread(ThreadAction::Delete), 112);
459 assert_action!(Action::AutoMod(AutoModAction::RuleCreate), 140);
460 assert_action!(Action::AutoMod(AutoModAction::RuleUpdate), 141);
461 assert_action!(Action::AutoMod(AutoModAction::RuleDelete), 142);
462 assert_action!(Action::AutoMod(AutoModAction::BlockMessage), 143);
463 assert_action!(Action::AutoMod(AutoModAction::FlagToChannel), 144);
464 assert_action!(Action::AutoMod(AutoModAction::UserCommunicationDisabled), 145);
465 assert_action!(Action::CreatorMonetization(CreatorMonetizationAction::RequestCreated), 150);
466 assert_action!(Action::CreatorMonetization(CreatorMonetizationAction::TermsAccepted), 151);
467 assert_action!(Action::VoiceChannelStatus(VoiceChannelStatusAction::StatusUpdate), 192);
468 assert_action!(Action::VoiceChannelStatus(VoiceChannelStatusAction::StatusDelete), 193);
469 assert_action!(Action::Unknown(234), 234);
470 }
471
472 #[test]
473 fn action_serde() {
474 use crate::json::{self, json};
475
476 #[derive(Debug, Deserialize, Serialize)]
477 struct T {
478 action: Action,
479 }
480
481 let value = json!({
482 "action": 234,
483 });
484
485 let value = json::from_value::<T>(value).unwrap();
486 assert_eq!(value.action.num(), 234);
487
488 assert!(matches!(value.action, Action::Unknown(234)));
489 }
490}