1use std::{
6 error::Error,
7 fmt::{Display, Formatter, Result as FmtResult},
8 time::{SystemTime, UNIX_EPOCH},
9};
10use twilight_model::id::marker::{ChannelMarker, RoleMarker};
11use twilight_model::id::Id;
12use twilight_model::util::Timestamp;
13
14pub const AUDIT_REASON_MAX: usize = 512;
16
17pub const AUTO_MODERATION_ACTION_BLOCK_CUSTOM_MESSAGE_LENGTH_MAX: usize = 150;
19
20pub const AUTO_MODERATION_METADATA_MENTION_TOTAL_LIMIT: u8 = 50;
22
23pub const AUTO_MODERATION_METADATA_KEYWORD_FILTER_MAX: usize = 1000;
25
26pub const AUTO_MODERATION_METADATA_KEYWORD_FILTER_LENGTH_MAX: usize = 60;
28
29pub const AUTO_MODERATION_METADATA_KEYWORD_ALLOW_LIST_MAX: usize = 100;
31
32pub const AUTO_MODERATION_METADATA_PRESET_ALLOW_LIST_MAX: usize = 1000;
34
35pub const AUTO_MODERATION_METADATA_PRESET_ALLOW_LIST_LENGTH_MAX: usize = 60;
37
38pub const AUTO_MODERATION_METADATA_KEYWORD_ALLOW_LIST_LENGTH_MAX: usize = 60;
40
41pub const AUTO_MODERATION_METADATA_REGEX_PATTERNS_MAX: usize = 10;
43
44pub const AUTO_MODERATION_METADATA_REGEX_PATTERNS_LENGTH_MAX: usize = 260;
46
47pub const AUTO_MODERATION_ACTION_METADATA_DURATION_SECONDS_MAX: u32 = 2_419_200;
49
50pub const AUTO_MODERATION_EXEMPT_ROLES_MAX: usize = 20;
52
53pub const AUTO_MODERATION_EXEMPT_CHANNELS_MAX: usize = 50;
55
56pub const CREATE_GUILD_BAN_DELETE_MESSAGE_SECONDS_MAX: u32 = 604_800;
58
59pub const COMMUNICATION_DISABLED_MAX_DURATION: i64 = 28 * 24 * 60 * 60;
61
62pub const GET_CHANNEL_MESSAGES_LIMIT_MAX: u16 = 100;
64
65pub const GET_CHANNEL_MESSAGES_LIMIT_MIN: u16 = 1;
67
68pub const GET_CURRENT_USER_GUILDS_LIMIT_MAX: u16 = 200;
70
71pub const GET_CURRENT_USER_GUILDS_LIMIT_MIN: u16 = 1;
73
74pub const GET_ENTITLEMENTS_LIMIT_MAX: u8 = 100;
76
77pub const GET_ENTITLEMENTS_LIMIT_MIN: u8 = 1;
79
80pub const GET_GUILD_AUDIT_LOG_LIMIT_MAX: u16 = 100;
82
83pub const GET_GUILD_AUDIT_LOG_LIMIT_MIN: u16 = 1;
85
86pub const GET_GUILD_BANS_LIMIT_MAX: u16 = 1000;
88
89pub const GET_GUILD_MEMBERS_LIMIT_MAX: u16 = 1000;
91
92pub const GET_GUILD_MEMBERS_LIMIT_MIN: u16 = 1;
94
95pub const GET_REACTIONS_LIMIT_MIN: u16 = 1;
97
98pub const GET_REACTIONS_LIMIT_MAX: u16 = 100;
100
101pub const GUILD_NAME_LENGTH_MAX: usize = 100;
103
104pub const GUILD_NAME_LENGTH_MIN: usize = 2;
106
107pub const GUILD_PRUNE_DAYS_MAX: u16 = 30;
109
110pub const GUILD_PRUNE_DAYS_MIN: u16 = 1;
112
113pub const INVITE_AGE_MAX: u32 = 604_800;
115
116pub const INVITE_USES_MAX: u16 = 100;
118
119pub const NICKNAME_LIMIT_MAX: usize = 32;
121
122pub const NICKNAME_LIMIT_MIN: usize = 1;
124
125pub const SCHEDULED_EVENT_DESCRIPTION_MAX: usize = 1000;
127
128pub const SCHEDULED_EVENT_DESCRIPTION_MIN: usize = 1;
130
131pub const SCHEDULED_EVENT_GET_USERS_MAX: u16 = 100;
133
134pub const SCHEDULED_EVENT_GET_USERS_MIN: u16 = 1;
136
137pub const SCHEDULED_EVENT_NAME_MAX: usize = 100;
139
140pub const SCHEDULED_EVENT_NAME_MIN: usize = 1;
142
143pub const SEARCH_GUILD_MEMBERS_LIMIT_MAX: u16 = 1000;
145
146pub const SEARCH_GUILD_MEMBERS_LIMIT_MIN: u16 = 1;
148
149pub const STAGE_TOPIC_LENGTH_MAX: usize = 120;
151
152pub const STAGE_TOPIC_LENGTH_MIN: usize = 1;
154
155pub const TEMPLATE_DESCRIPTION_LENGTH_MAX: usize = 120;
157
158pub const TEMPLATE_NAME_LENGTH_MAX: usize = 100;
160
161pub const TEMPLATE_NAME_LENGTH_MIN: usize = 1;
163
164pub const USERNAME_LIMIT_MAX: usize = 32;
166
167pub const USERNAME_LIMIT_MIN: usize = 2;
169
170pub const WEBHOOK_USERNAME_LIMIT_MAX: usize = 80;
172
173pub const WEBHOOK_USERNAME_LIMIT_MIN: usize = 2;
175
176const USERNAME_INVALID_SUBSTRINGS: [&str; 5] = ["@", "#", ":", "```", "discord"];
178
179const USERNAME_INVALID_STRINGS: [&str; 2] = ["everyone", "here"];
181
182const WEBHOOK_INVALID_STRINGS: [&str; 1] = ["clyde"];
184
185#[derive(Debug)]
187pub struct ValidationError {
188 kind: ValidationErrorType,
190}
191
192impl ValidationError {
193 #[must_use = "retrieving the type has no effect if left unused"]
195 pub const fn kind(&self) -> &ValidationErrorType {
196 &self.kind
197 }
198
199 #[allow(clippy::unused_self)]
201 #[must_use = "consuming the error and retrieving the source has no effect if left unused"]
202 pub fn into_source(self) -> Option<Box<dyn Error + Send + Sync>> {
203 None
204 }
205
206 #[must_use = "consuming the error into its parts has no effect if left unused"]
208 pub fn into_parts(self) -> (ValidationErrorType, Option<Box<dyn Error + Send + Sync>>) {
209 (self.kind, None)
210 }
211}
212
213impl Display for ValidationError {
214 #[allow(clippy::too_many_lines)]
215 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
216 match &self.kind {
217 ValidationErrorType::AuditReason { len } => {
218 f.write_str("provided audit reason length is ")?;
219 Display::fmt(len, f)?;
220 f.write_str(", but it must be at most ")?;
221
222 Display::fmt(&AUDIT_REASON_MAX, f)
223 }
224 ValidationErrorType::AutoModerationBlockActionCustomMessageLimit { len } => {
225 f.write_str("provided auto moderation block action custom message length is ")?;
226 Display::fmt(len, f)?;
227 f.write_str(", but it must be at most ")?;
228
229 Display::fmt(&AUTO_MODERATION_ACTION_BLOCK_CUSTOM_MESSAGE_LENGTH_MAX, f)
230 }
231 ValidationErrorType::AutoModerationMetadataMentionTotalLimit { limit } => {
232 f.write_str("provided auto moderation metadata mention_total_limit is ")?;
233 Display::fmt(limit, f)?;
234 f.write_str(", but it must be at most ")?;
235
236 Display::fmt(&AUTO_MODERATION_METADATA_MENTION_TOTAL_LIMIT, f)
237 }
238 ValidationErrorType::AutoModerationMetadataAllowList { len } => {
239 f.write_str("provided auto moderation metadata allow_list length is ")?;
240 Display::fmt(len, f)?;
241 f.write_str(", but it must be at most ")?;
242
243 Display::fmt(&AUTO_MODERATION_METADATA_KEYWORD_ALLOW_LIST_MAX, f)
244 }
245 ValidationErrorType::AutoModerationMetadataAllowListItem { len, substring } => {
246 f.write_str("provided auto moderation metadata allow_list item ")?;
247 Display::fmt(substring, f)?;
248 f.write_str(" length is ")?;
249 Display::fmt(len, f)?;
250 f.write_str(", but it must be at most ")?;
251
252 Display::fmt(&AUTO_MODERATION_METADATA_KEYWORD_ALLOW_LIST_LENGTH_MAX, f)
253 }
254 ValidationErrorType::AutoModerationMetadataKeywordFilter { len } => {
255 f.write_str("provided auto moderation metadata keyword_filter length is ")?;
256 Display::fmt(len, f)?;
257 f.write_str(", but it must be at most ")?;
258
259 Display::fmt(&AUTO_MODERATION_METADATA_KEYWORD_FILTER_MAX, f)
260 }
261 ValidationErrorType::AutoModerationMetadataKeywordFilterItem { len, substring } => {
262 f.write_str("provided auto moderation metadata keyword_filter item ")?;
263 Display::fmt(substring, f)?;
264 f.write_str(" length is ")?;
265 Display::fmt(len, f)?;
266 f.write_str(", but it must be at most ")?;
267
268 Display::fmt(&AUTO_MODERATION_METADATA_KEYWORD_FILTER_LENGTH_MAX, f)
269 }
270 ValidationErrorType::AutoModerationMetadataPresetAllowList { len } => {
271 f.write_str("provided auto moderation metadata allow_list length is ")?;
272 Display::fmt(len, f)?;
273 f.write_str(", but it must be at most ")?;
274
275 Display::fmt(&AUTO_MODERATION_METADATA_PRESET_ALLOW_LIST_MAX, f)
276 }
277 ValidationErrorType::AutoModerationMetadataPresetAllowListItem { len, substring } => {
278 f.write_str("provided auto moderation metadata allow_list item ")?;
279 Display::fmt(substring, f)?;
280 f.write_str(" length is ")?;
281 Display::fmt(len, f)?;
282 f.write_str(", but it must be at most ")?;
283
284 Display::fmt(&AUTO_MODERATION_METADATA_PRESET_ALLOW_LIST_LENGTH_MAX, f)
285 }
286 ValidationErrorType::AutoModerationActionMetadataDurationSeconds { seconds } => {
287 f.write_str("provided auto moderation action timeout duration is ")?;
288 Display::fmt(seconds, f)?;
289 f.write_str(", but it must be at most ")?;
290
291 Display::fmt(&AUTO_MODERATION_ACTION_METADATA_DURATION_SECONDS_MAX, f)
292 }
293 ValidationErrorType::AutoModerationMetadataRegexPatterns { len } => {
294 f.write_str("provided auto moderation metadata regex_patterns length is ")?;
295 Display::fmt(len, f)?;
296 f.write_str(", but it must be at most ")?;
297
298 Display::fmt(&AUTO_MODERATION_METADATA_REGEX_PATTERNS_MAX, f)
299 }
300 ValidationErrorType::AutoModerationMetadataRegexPatternsItem { len, substring } => {
301 f.write_str("provided auto moderation metadata regex_patterns item ")?;
302 Display::fmt(substring, f)?;
303 f.write_str(" length is ")?;
304 Display::fmt(len, f)?;
305 f.write_str(", but it must be at most ")?;
306
307 Display::fmt(&AUTO_MODERATION_METADATA_REGEX_PATTERNS_LENGTH_MAX, f)
308 }
309 ValidationErrorType::AutoModerationExemptRoles { len } => {
310 f.write_str("provided auto moderation exempt_roles length is ")?;
311 Display::fmt(len, f)?;
312 f.write_str(", but it must be at most ")?;
313
314 Display::fmt(&AUTO_MODERATION_EXEMPT_ROLES_MAX, f)
315 }
316 ValidationErrorType::AutoModerationExemptChannels { len } => {
317 f.write_str("provided auto moderation exempt_channels length is ")?;
318 Display::fmt(len, f)?;
319 f.write_str(", but it must be at most ")?;
320
321 Display::fmt(&AUTO_MODERATION_EXEMPT_CHANNELS_MAX, f)
322 }
323 ValidationErrorType::CreateGuildBanDeleteMessageSeconds {
324 seconds: delete_message_seconds,
325 } => {
326 f.write_str("provided create guild ban delete_message_seconds is ")?;
327 Display::fmt(delete_message_seconds, f)?;
328 f.write_str(", but it must be at most ")?;
329
330 Display::fmt(&CREATE_GUILD_BAN_DELETE_MESSAGE_SECONDS_MAX, f)
331 }
332 ValidationErrorType::CommunicationDisabledUntil { .. } => {
333 f.write_str("provided timestamp is too far in the future")
334 }
335 ValidationErrorType::GetChannelMessages { limit } => {
336 f.write_str("provided get guild members limit is ")?;
337 Display::fmt(limit, f)?;
338 f.write_str(", but it must be at least ")?;
339 Display::fmt(&GET_CHANNEL_MESSAGES_LIMIT_MIN, f)?;
340 f.write_str(" and at most ")?;
341
342 Display::fmt(&GET_CHANNEL_MESSAGES_LIMIT_MAX, f)
343 }
344 ValidationErrorType::GetCurrentUserGuilds { limit } => {
345 f.write_str("provided get current user guilds limit is ")?;
346 Display::fmt(limit, f)?;
347 f.write_str(", but it must be at least ")?;
348 Display::fmt(&GET_CURRENT_USER_GUILDS_LIMIT_MIN, f)?;
349 f.write_str(" and at most ")?;
350
351 Display::fmt(&GET_CURRENT_USER_GUILDS_LIMIT_MAX, f)
352 }
353 ValidationErrorType::GetEntitlements { limit } => {
354 f.write_str("provided get entitlements limit is ")?;
355 Display::fmt(limit, f)?;
356 f.write_str(", but it must be at least ")?;
357 Display::fmt(&GET_ENTITLEMENTS_LIMIT_MIN, f)?;
358 f.write_str(" and at most ")?;
359
360 Display::fmt(&GET_ENTITLEMENTS_LIMIT_MAX, f)
361 }
362 ValidationErrorType::GetGuildAuditLog { limit } => {
363 f.write_str("provided get guild audit log limit is ")?;
364 Display::fmt(limit, f)?;
365 f.write_str(", but it must be at least ")?;
366 Display::fmt(&GET_GUILD_MEMBERS_LIMIT_MIN, f)?;
367 f.write_str(" and at most ")?;
368
369 Display::fmt(&GET_GUILD_MEMBERS_LIMIT_MAX, f)
370 }
371 ValidationErrorType::GetGuildBans { limit } => {
372 f.write_str("provided get guild bans limit is ")?;
373 Display::fmt(limit, f)?;
374 f.write_str(", but it must be at most ")?;
375
376 Display::fmt(&GET_GUILD_BANS_LIMIT_MAX, f)
377 }
378 ValidationErrorType::GetGuildMembers { limit } => {
379 f.write_str("provided get guild members limit is ")?;
380 Display::fmt(limit, f)?;
381 f.write_str(", but it must be at least ")?;
382 Display::fmt(&GET_GUILD_MEMBERS_LIMIT_MIN, f)?;
383 f.write_str(" and at most ")?;
384
385 Display::fmt(&GET_GUILD_MEMBERS_LIMIT_MAX, f)
386 }
387 ValidationErrorType::GetReactions { limit } => {
388 f.write_str("provided get reactions limit is ")?;
389 Display::fmt(limit, f)?;
390 f.write_str(", but it must be at least ")?;
391 Display::fmt(&GET_REACTIONS_LIMIT_MIN, f)?;
392 f.write_str(" and at most ")?;
393
394 Display::fmt(&GET_REACTIONS_LIMIT_MAX, f)
395 }
396 ValidationErrorType::GuildName { len } => {
397 f.write_str("provided guild name length is ")?;
398 Display::fmt(len, f)?;
399 f.write_str(", but it must be at least ")?;
400 Display::fmt(&GUILD_NAME_LENGTH_MIN, f)?;
401 f.write_str(" and at most ")?;
402
403 Display::fmt(&GUILD_NAME_LENGTH_MAX, f)
404 }
405 ValidationErrorType::GuildPruneDays { days } => {
406 f.write_str("provided prune days is ")?;
407 Display::fmt(days, f)?;
408 f.write_str(", but it must be at least ")?;
409 Display::fmt(&GUILD_PRUNE_DAYS_MIN, f)?;
410 f.write_str(" and at most ")?;
411
412 Display::fmt(&GUILD_PRUNE_DAYS_MAX, f)
413 }
414 ValidationErrorType::InviteMaxAge { max_age } => {
415 f.write_str("provided invite max_age is ")?;
416 Display::fmt(max_age, f)?;
417 f.write_str(", but it must be at most ")?;
418
419 Display::fmt(&INVITE_AGE_MAX, f)
420 }
421 ValidationErrorType::InviteMaxUses { max_uses } => {
422 f.write_str("provided invite max_uses is ")?;
423 Display::fmt(max_uses, f)?;
424 f.write_str(", but it must be at most ")?;
425
426 Display::fmt(&INVITE_USES_MAX, f)
427 }
428 ValidationErrorType::Nickname { len } => {
429 f.write_str("provided nickname length is ")?;
430 Display::fmt(len, f)?;
431 f.write_str(", but it must be at least ")?;
432 Display::fmt(&NICKNAME_LIMIT_MIN, f)?;
433 f.write_str(" and at most ")?;
434
435 Display::fmt(&NICKNAME_LIMIT_MAX, f)
436 }
437 ValidationErrorType::ScheduledEventDescription { len } => {
438 f.write_str("provided scheduled event description is length is ")?;
439 Display::fmt(len, f)?;
440 f.write_str(", but it must be at least ")?;
441 Display::fmt(&SCHEDULED_EVENT_DESCRIPTION_MIN, f)?;
442 f.write_str(" and at most ")?;
443
444 Display::fmt(&SCHEDULED_EVENT_DESCRIPTION_MAX, f)
445 }
446 ValidationErrorType::ScheduledEventGetUsers { limit } => {
447 f.write_str("provided scheduled event get users limit is ")?;
448 Display::fmt(limit, f)?;
449 f.write_str(", but it must be at least ")?;
450 Display::fmt(&SCHEDULED_EVENT_GET_USERS_MIN, f)?;
451 f.write_str(" and at most ")?;
452
453 Display::fmt(&SCHEDULED_EVENT_GET_USERS_MAX, f)
454 }
455 ValidationErrorType::ScheduledEventName { len } => {
456 f.write_str("provided scheduled event name is length is ")?;
457 Display::fmt(len, f)?;
458 f.write_str(", but it must be at least ")?;
459 Display::fmt(&SCHEDULED_EVENT_NAME_MIN, f)?;
460 f.write_str(" and at most ")?;
461
462 Display::fmt(&SCHEDULED_EVENT_NAME_MAX, f)
463 }
464 ValidationErrorType::SearchGuildMembers { limit } => {
465 f.write_str("provided search guild members limit is ")?;
466 Display::fmt(limit, f)?;
467 f.write_str(", but it must be at least ")?;
468 Display::fmt(&SEARCH_GUILD_MEMBERS_LIMIT_MIN, f)?;
469 f.write_str(" and at most ")?;
470
471 Display::fmt(&SEARCH_GUILD_MEMBERS_LIMIT_MAX, f)
472 }
473 ValidationErrorType::StageTopic { len } => {
474 f.write_str("provided stage instance topic length is ")?;
475 Display::fmt(len, f)?;
476 f.write_str(", but it must be at least ")?;
477 Display::fmt(&STAGE_TOPIC_LENGTH_MIN, f)?;
478 f.write_str(" and at most ")?;
479
480 Display::fmt(&STAGE_TOPIC_LENGTH_MAX, f)
481 }
482 ValidationErrorType::TemplateDescription { len } => {
483 f.write_str("provided guild template description topic length is ")?;
484 Display::fmt(len, f)?;
485 f.write_str(", but it must be at most ")?;
486
487 Display::fmt(&TEMPLATE_DESCRIPTION_LENGTH_MAX, f)
488 }
489 ValidationErrorType::TemplateName { len } => {
490 f.write_str("provided guild template name length is ")?;
491 Display::fmt(len, f)?;
492 f.write_str(", but it must be at least ")?;
493 Display::fmt(&TEMPLATE_NAME_LENGTH_MIN, f)?;
494 f.write_str(" and at most ")?;
495
496 Display::fmt(&TEMPLATE_NAME_LENGTH_MAX, f)
497 }
498 ValidationErrorType::Username { len, substring }
499 | ValidationErrorType::WebhookUsername { len, substring } => {
500 f.write_str("provided username")?;
501
502 if let Some(len) = len {
503 f.write_str(" length is ")?;
504 Display::fmt(len, f)?;
505 f.write_str(", but it must be at least ")?;
506 Display::fmt(&USERNAME_LIMIT_MIN, f)?;
507 f.write_str(" and at most ")?;
508 Display::fmt(&USERNAME_LIMIT_MAX, f)?;
509 }
510
511 if let Some(substring) = substring {
512 if len.is_some() {
513 f.write_str(", and")?;
514 }
515
516 f.write_str(" cannot contain ")?;
517 Display::fmt(substring, f)?;
518 }
519
520 Ok(())
521 }
522 }
523 }
524}
525
526impl Error for ValidationError {}
527
528#[derive(Debug)]
530pub enum ValidationErrorType {
531 AuditReason {
533 len: usize,
535 },
536 AutoModerationBlockActionCustomMessageLimit {
538 len: usize,
540 },
541 AutoModerationMetadataMentionTotalLimit {
543 limit: u8,
545 },
546 AutoModerationMetadataKeywordFilter {
548 len: usize,
550 },
551 AutoModerationMetadataKeywordFilterItem {
553 len: usize,
555 substring: String,
557 },
558 AutoModerationMetadataAllowList {
560 len: usize,
562 },
563 AutoModerationMetadataAllowListItem {
565 len: usize,
567 substring: String,
569 },
570 AutoModerationMetadataPresetAllowList {
572 len: usize,
574 },
575 AutoModerationMetadataPresetAllowListItem {
577 len: usize,
579 substring: String,
581 },
582 AutoModerationActionMetadataDurationSeconds {
584 seconds: u32,
586 },
587 AutoModerationMetadataRegexPatterns {
589 len: usize,
591 },
592 AutoModerationMetadataRegexPatternsItem {
594 len: usize,
596 substring: String,
598 },
599 AutoModerationExemptRoles {
601 len: usize,
603 },
604 AutoModerationExemptChannels {
606 len: usize,
608 },
609 CreateGuildBanDeleteMessageSeconds {
611 seconds: u32,
613 },
614 CommunicationDisabledUntil {
616 timestamp: Timestamp,
618 },
619 GetChannelMessages {
621 limit: u16,
623 },
624 GetCurrentUserGuilds {
626 limit: u16,
628 },
629 GetEntitlements {
631 limit: u8,
633 },
634 GetGuildAuditLog {
636 limit: u16,
638 },
639 GetGuildBans {
641 limit: u16,
643 },
644 GetGuildMembers {
646 limit: u16,
648 },
649 GetReactions {
651 limit: u16,
653 },
654 GuildName {
656 len: usize,
658 },
659 GuildPruneDays {
661 days: u16,
663 },
664 InviteMaxAge {
666 max_age: u32,
668 },
669 InviteMaxUses {
671 max_uses: u16,
673 },
674 Nickname {
676 len: usize,
678 },
679 ScheduledEventDescription {
681 len: usize,
683 },
684 ScheduledEventGetUsers {
686 limit: u16,
688 },
689 ScheduledEventName {
691 len: usize,
693 },
694 SearchGuildMembers {
696 limit: u16,
698 },
699 StageTopic {
701 len: usize,
703 },
704 TemplateDescription {
706 len: usize,
708 },
709 TemplateName {
711 len: usize,
713 },
714 Username {
716 len: Option<usize>,
718 substring: Option<&'static str>,
720 },
721 WebhookUsername {
723 len: Option<usize>,
725 substring: Option<&'static str>,
727 },
728}
729
730pub fn audit_reason(audit_reason: impl AsRef<str>) -> Result<(), ValidationError> {
742 let len = audit_reason.as_ref().chars().count();
743
744 if len <= AUDIT_REASON_MAX {
745 Ok(())
746 } else {
747 Err(ValidationError {
748 kind: ValidationErrorType::AuditReason { len },
749 })
750 }
751}
752
753pub fn auto_moderation_block_action_custom_message_limit(
766 custom_message: impl AsRef<str>,
767) -> Result<(), ValidationError> {
768 let len = custom_message.as_ref().chars().count();
769
770 if len <= AUTO_MODERATION_ACTION_BLOCK_CUSTOM_MESSAGE_LENGTH_MAX {
771 Ok(())
772 } else {
773 Err(ValidationError {
774 kind: ValidationErrorType::AutoModerationBlockActionCustomMessageLimit { len },
775 })
776 }
777}
778
779pub const fn auto_moderation_metadata_mention_total_limit(
792 limit: u8,
793) -> Result<(), ValidationError> {
794 if limit <= AUTO_MODERATION_METADATA_MENTION_TOTAL_LIMIT {
795 Ok(())
796 } else {
797 Err(ValidationError {
798 kind: ValidationErrorType::AutoModerationMetadataMentionTotalLimit { limit },
799 })
800 }
801}
802
803pub fn auto_moderation_metadata_keyword_filter(
820 keywords: &[impl AsRef<str>],
821) -> Result<(), ValidationError> {
822 let len = keywords.len();
823
824 if len <= AUTO_MODERATION_METADATA_KEYWORD_FILTER_MAX {
825 for keyword in keywords {
826 auto_moderation_metadata_keyword_filter_item(keyword)?;
827 }
828
829 Ok(())
830 } else {
831 Err(ValidationError {
832 kind: ValidationErrorType::AutoModerationMetadataKeywordFilter { len },
833 })
834 }
835}
836
837pub fn auto_moderation_metadata_keyword_filter_item(
850 keyword: impl AsRef<str>,
851) -> Result<(), ValidationError> {
852 let len = keyword.as_ref().chars().count();
853
854 if len <= AUTO_MODERATION_METADATA_KEYWORD_FILTER_LENGTH_MAX {
855 Ok(())
856 } else {
857 Err(ValidationError {
858 kind: ValidationErrorType::AutoModerationMetadataKeywordFilterItem {
859 len,
860 substring: keyword.as_ref().to_string(),
861 },
862 })
863 }
864}
865
866pub fn auto_moderation_metadata_keyword_allow_list(
883 keywords: &[impl AsRef<str>],
884) -> Result<(), ValidationError> {
885 let len = keywords.len();
886
887 if len <= AUTO_MODERATION_METADATA_KEYWORD_ALLOW_LIST_MAX {
888 for keyword in keywords {
889 auto_moderation_metadata_keyword_allow_list_item(keyword)?;
890 }
891
892 Ok(())
893 } else {
894 Err(ValidationError {
895 kind: ValidationErrorType::AutoModerationMetadataAllowList { len },
896 })
897 }
898}
899
900pub fn auto_moderation_metadata_keyword_allow_list_item(
913 keyword: impl AsRef<str>,
914) -> Result<(), ValidationError> {
915 let len = keyword.as_ref().chars().count();
916
917 if len <= AUTO_MODERATION_METADATA_KEYWORD_FILTER_LENGTH_MAX {
918 Ok(())
919 } else {
920 Err(ValidationError {
921 kind: ValidationErrorType::AutoModerationMetadataAllowListItem {
922 len,
923 substring: keyword.as_ref().to_string(),
924 },
925 })
926 }
927}
928
929pub fn auto_moderation_metadata_preset_allow_list(
946 keywords: &[impl AsRef<str>],
947) -> Result<(), ValidationError> {
948 let len = keywords.len();
949
950 if len <= AUTO_MODERATION_METADATA_PRESET_ALLOW_LIST_MAX {
951 for keyword in keywords {
952 auto_moderation_metadata_preset_allow_list_item(keyword)?;
953 }
954
955 Ok(())
956 } else {
957 Err(ValidationError {
958 kind: ValidationErrorType::AutoModerationMetadataPresetAllowList { len },
959 })
960 }
961}
962
963pub fn auto_moderation_metadata_preset_allow_list_item(
976 keyword: impl AsRef<str>,
977) -> Result<(), ValidationError> {
978 let len = keyword.as_ref().chars().count();
979
980 if len <= AUTO_MODERATION_METADATA_PRESET_ALLOW_LIST_LENGTH_MAX {
981 Ok(())
982 } else {
983 Err(ValidationError {
984 kind: ValidationErrorType::AutoModerationMetadataPresetAllowListItem {
985 len,
986 substring: keyword.as_ref().to_string(),
987 },
988 })
989 }
990}
991
992pub fn auto_moderation_metadata_regex_patterns(
1009 patterns: &[impl AsRef<str>],
1010) -> Result<(), ValidationError> {
1011 let len = patterns.len();
1012
1013 if len <= AUTO_MODERATION_METADATA_REGEX_PATTERNS_MAX {
1014 for pattern in patterns {
1015 auto_moderation_metadata_regex_patterns_item(pattern)?;
1016 }
1017
1018 Ok(())
1019 } else {
1020 Err(ValidationError {
1021 kind: ValidationErrorType::AutoModerationMetadataRegexPatterns { len },
1022 })
1023 }
1024}
1025
1026pub fn auto_moderation_metadata_regex_patterns_item(
1039 pattern: impl AsRef<str>,
1040) -> Result<(), ValidationError> {
1041 let len = pattern.as_ref().chars().count();
1042
1043 if len <= AUTO_MODERATION_METADATA_REGEX_PATTERNS_LENGTH_MAX {
1044 Ok(())
1045 } else {
1046 Err(ValidationError {
1047 kind: ValidationErrorType::AutoModerationMetadataRegexPatternsItem {
1048 len,
1049 substring: pattern.as_ref().to_string(),
1050 },
1051 })
1052 }
1053}
1054
1055pub const fn auto_moderation_action_metadata_duration_seconds(
1069 seconds: u32,
1070) -> Result<(), ValidationError> {
1071 if seconds <= AUTO_MODERATION_ACTION_METADATA_DURATION_SECONDS_MAX {
1072 Ok(())
1073 } else {
1074 Err(ValidationError {
1075 kind: ValidationErrorType::AutoModerationActionMetadataDurationSeconds { seconds },
1076 })
1077 }
1078}
1079
1080pub const fn auto_moderation_exempt_roles(roles: &[Id<RoleMarker>]) -> Result<(), ValidationError> {
1093 let len = roles.len();
1094
1095 if len <= AUTO_MODERATION_EXEMPT_ROLES_MAX {
1096 Ok(())
1097 } else {
1098 Err(ValidationError {
1099 kind: ValidationErrorType::AutoModerationExemptRoles { len },
1100 })
1101 }
1102}
1103
1104pub const fn auto_moderation_exempt_channels(
1117 channels: &[Id<ChannelMarker>],
1118) -> Result<(), ValidationError> {
1119 let len = channels.len();
1120
1121 if len <= AUTO_MODERATION_EXEMPT_CHANNELS_MAX {
1122 Ok(())
1123 } else {
1124 Err(ValidationError {
1125 kind: ValidationErrorType::AutoModerationExemptChannels { len },
1126 })
1127 }
1128}
1129
1130pub const fn create_guild_ban_delete_message_seconds(seconds: u32) -> Result<(), ValidationError> {
1144 if seconds <= CREATE_GUILD_BAN_DELETE_MESSAGE_SECONDS_MAX {
1145 Ok(())
1146 } else {
1147 Err(ValidationError {
1148 kind: ValidationErrorType::CreateGuildBanDeleteMessageSeconds { seconds },
1149 })
1150 }
1151}
1152
1153#[allow(clippy::cast_possible_wrap)] pub fn communication_disabled_until(timestamp: Timestamp) -> Result<(), ValidationError> {
1160 let now = SystemTime::now()
1161 .duration_since(UNIX_EPOCH)
1162 .map_err(|_| ValidationError {
1163 kind: ValidationErrorType::CommunicationDisabledUntil { timestamp },
1164 })?;
1165
1166 let end = timestamp.as_secs();
1167
1168 if end - now.as_secs() as i64 <= COMMUNICATION_DISABLED_MAX_DURATION {
1169 Ok(())
1170 } else {
1171 Err(ValidationError {
1172 kind: ValidationErrorType::CommunicationDisabledUntil { timestamp },
1173 })
1174 }
1175}
1176
1177pub const fn get_channel_messages_limit(limit: u16) -> Result<(), ValidationError> {
1190 if limit >= GET_CHANNEL_MESSAGES_LIMIT_MIN && limit <= GET_CHANNEL_MESSAGES_LIMIT_MAX {
1191 Ok(())
1192 } else {
1193 Err(ValidationError {
1194 kind: ValidationErrorType::GetChannelMessages { limit },
1195 })
1196 }
1197}
1198
1199pub const fn get_current_user_guilds_limit(limit: u16) -> Result<(), ValidationError> {
1212 if limit >= GET_CURRENT_USER_GUILDS_LIMIT_MIN && limit <= GET_CURRENT_USER_GUILDS_LIMIT_MAX {
1213 Ok(())
1214 } else {
1215 Err(ValidationError {
1216 kind: ValidationErrorType::GetCurrentUserGuilds { limit },
1217 })
1218 }
1219}
1220
1221pub const fn get_entitlements_limit(limit: u8) -> Result<(), ValidationError> {
1234 if limit >= GET_ENTITLEMENTS_LIMIT_MIN && limit <= GET_ENTITLEMENTS_LIMIT_MAX {
1235 Ok(())
1236 } else {
1237 Err(ValidationError {
1238 kind: ValidationErrorType::GetEntitlements { limit },
1239 })
1240 }
1241}
1242
1243pub const fn get_guild_audit_log_limit(limit: u16) -> Result<(), ValidationError> {
1256 if limit >= GET_GUILD_AUDIT_LOG_LIMIT_MIN && limit <= GET_GUILD_AUDIT_LOG_LIMIT_MAX {
1257 Ok(())
1258 } else {
1259 Err(ValidationError {
1260 kind: ValidationErrorType::GetGuildAuditLog { limit },
1261 })
1262 }
1263}
1264
1265pub const fn get_guild_bans_limit(limit: u16) -> Result<(), ValidationError> {
1277 if limit <= GET_GUILD_BANS_LIMIT_MAX {
1278 Ok(())
1279 } else {
1280 Err(ValidationError {
1281 kind: ValidationErrorType::GetGuildBans { limit },
1282 })
1283 }
1284}
1285
1286pub const fn get_guild_members_limit(limit: u16) -> Result<(), ValidationError> {
1299 if limit >= GET_GUILD_MEMBERS_LIMIT_MIN && limit <= GET_GUILD_MEMBERS_LIMIT_MAX {
1300 Ok(())
1301 } else {
1302 Err(ValidationError {
1303 kind: ValidationErrorType::GetGuildMembers { limit },
1304 })
1305 }
1306}
1307
1308pub const fn get_reactions_limit(limit: u16) -> Result<(), ValidationError> {
1320 if limit >= GET_REACTIONS_LIMIT_MIN && limit <= GET_REACTIONS_LIMIT_MAX {
1321 Ok(())
1322 } else {
1323 Err(ValidationError {
1324 kind: ValidationErrorType::GetReactions { limit },
1325 })
1326 }
1327}
1328
1329pub fn guild_name(name: impl AsRef<str>) -> Result<(), ValidationError> {
1341 let len = name.as_ref().chars().count();
1342
1343 if (GUILD_NAME_LENGTH_MIN..=GUILD_NAME_LENGTH_MAX).contains(&len) {
1344 Ok(())
1345 } else {
1346 Err(ValidationError {
1347 kind: ValidationErrorType::GuildName { len },
1348 })
1349 }
1350}
1351
1352pub const fn guild_prune_days(days: u16) -> Result<(), ValidationError> {
1364 if days >= GUILD_PRUNE_DAYS_MIN && days <= GUILD_PRUNE_DAYS_MAX {
1365 Ok(())
1366 } else {
1367 Err(ValidationError {
1368 kind: ValidationErrorType::GuildPruneDays { days },
1369 })
1370 }
1371}
1372
1373pub const fn invite_max_age(max_age: u32) -> Result<(), ValidationError> {
1385 if max_age <= INVITE_AGE_MAX {
1386 Ok(())
1387 } else {
1388 Err(ValidationError {
1389 kind: ValidationErrorType::InviteMaxAge { max_age },
1390 })
1391 }
1392}
1393
1394pub const fn invite_max_uses(max_uses: u16) -> Result<(), ValidationError> {
1406 if max_uses <= INVITE_USES_MAX {
1407 Ok(())
1408 } else {
1409 Err(ValidationError {
1410 kind: ValidationErrorType::InviteMaxUses { max_uses },
1411 })
1412 }
1413}
1414
1415pub fn nickname(nickname: impl AsRef<str>) -> Result<(), ValidationError> {
1427 let len = nickname.as_ref().chars().count();
1428
1429 if (NICKNAME_LIMIT_MIN..=NICKNAME_LIMIT_MAX).contains(&len) {
1430 Ok(())
1431 } else {
1432 Err(ValidationError {
1433 kind: ValidationErrorType::Nickname { len },
1434 })
1435 }
1436}
1437
1438pub fn scheduled_event_description(description: impl AsRef<str>) -> Result<(), ValidationError> {
1452 let len = description.as_ref().chars().count();
1453
1454 if (SCHEDULED_EVENT_DESCRIPTION_MIN..=SCHEDULED_EVENT_DESCRIPTION_MAX).contains(&len) {
1455 Ok(())
1456 } else {
1457 Err(ValidationError {
1458 kind: ValidationErrorType::ScheduledEventDescription { len },
1459 })
1460 }
1461}
1462
1463pub const fn scheduled_event_get_users(limit: u16) -> Result<(), ValidationError> {
1476 if limit >= SCHEDULED_EVENT_GET_USERS_MIN && limit <= SCHEDULED_EVENT_GET_USERS_MAX {
1477 Ok(())
1478 } else {
1479 Err(ValidationError {
1480 kind: ValidationErrorType::ScheduledEventGetUsers { limit },
1481 })
1482 }
1483}
1484
1485pub fn scheduled_event_name(name: impl AsRef<str>) -> Result<(), ValidationError> {
1497 let len = name.as_ref().chars().count();
1498
1499 if (SCHEDULED_EVENT_NAME_MIN..=SCHEDULED_EVENT_NAME_MAX).contains(&len) {
1500 Ok(())
1501 } else {
1502 Err(ValidationError {
1503 kind: ValidationErrorType::ScheduledEventName { len },
1504 })
1505 }
1506}
1507
1508pub const fn search_guild_members_limit(limit: u16) -> Result<(), ValidationError> {
1521 if limit >= SEARCH_GUILD_MEMBERS_LIMIT_MIN && limit <= SEARCH_GUILD_MEMBERS_LIMIT_MAX {
1522 Ok(())
1523 } else {
1524 Err(ValidationError {
1525 kind: ValidationErrorType::SearchGuildMembers { limit },
1526 })
1527 }
1528}
1529
1530pub fn stage_topic(topic: impl AsRef<str>) -> Result<(), ValidationError> {
1542 let len = topic.as_ref().chars().count();
1543
1544 if (STAGE_TOPIC_LENGTH_MIN..=STAGE_TOPIC_LENGTH_MAX).contains(&len) {
1545 Ok(())
1546 } else {
1547 Err(ValidationError {
1548 kind: ValidationErrorType::StageTopic { len },
1549 })
1550 }
1551}
1552
1553pub fn template_description(description: impl AsRef<str>) -> Result<(), ValidationError> {
1565 let len = description.as_ref().chars().count();
1566
1567 if len <= TEMPLATE_DESCRIPTION_LENGTH_MAX {
1568 Ok(())
1569 } else {
1570 Err(ValidationError {
1571 kind: ValidationErrorType::TemplateDescription { len },
1572 })
1573 }
1574}
1575
1576pub fn template_name(name: impl AsRef<str>) -> Result<(), ValidationError> {
1588 let len = name.as_ref().chars().count();
1589
1590 if (TEMPLATE_NAME_LENGTH_MIN..=TEMPLATE_NAME_LENGTH_MAX).contains(&len) {
1591 Ok(())
1592 } else {
1593 Err(ValidationError {
1594 kind: ValidationErrorType::TemplateName { len },
1595 })
1596 }
1597}
1598
1599pub fn username(value: impl AsRef<str>) -> Result<(), ValidationError> {
1612 let value = value.as_ref();
1613 let len = value.chars().count();
1614
1615 let range = USERNAME_LIMIT_MIN..=USERNAME_LIMIT_MAX;
1616 let invalid_len = (!range.contains(&len)).then_some(len);
1617
1618 let invalid_substring = USERNAME_INVALID_SUBSTRINGS
1619 .into_iter()
1620 .find(|invalid_substring| value.contains(invalid_substring))
1621 .or_else(|| {
1622 USERNAME_INVALID_STRINGS
1623 .into_iter()
1624 .find(|invalid_string| value == *invalid_string)
1625 });
1626
1627 if invalid_len.is_none() && invalid_substring.is_none() {
1628 Ok(())
1629 } else {
1630 Err(ValidationError {
1631 kind: ValidationErrorType::Username {
1632 len: invalid_len,
1633 substring: invalid_substring,
1634 },
1635 })
1636 }
1637}
1638
1639pub fn webhook_username(value: impl AsRef<str>) -> Result<(), ValidationError> {
1652 let value = value.as_ref();
1653 let len = value.chars().count();
1654
1655 let range = WEBHOOK_USERNAME_LIMIT_MIN..=WEBHOOK_USERNAME_LIMIT_MAX;
1656 let invalid_len = (!range.contains(&len)).then_some(len);
1657
1658 let invalid_substring = WEBHOOK_INVALID_STRINGS
1659 .into_iter()
1660 .find(|invalid_string| value == *invalid_string);
1661
1662 if invalid_len.is_none() && invalid_substring.is_none() {
1663 Ok(())
1664 } else {
1665 Err(ValidationError {
1666 kind: ValidationErrorType::WebhookUsername {
1667 len: invalid_len,
1668 substring: invalid_substring,
1669 },
1670 })
1671 }
1672}
1673
1674#[cfg(test)]
1675mod tests {
1676 use super::*;
1677
1678 #[test]
1679 fn username_variants() {
1680 let expected = format!(
1681 "provided username length is 200, but it must be at least {USERNAME_LIMIT_MIN} and at \
1682 most {USERNAME_LIMIT_MAX}, and cannot contain :"
1683 );
1684 let actual = ValidationError {
1685 kind: ValidationErrorType::Username {
1686 len: Some(200),
1687 substring: Some(":"),
1688 },
1689 };
1690 assert_eq!(expected, actual.to_string());
1691
1692 let expected = format!(
1693 "provided username length is 200, but it must be at least {USERNAME_LIMIT_MIN} and at \
1694 most {USERNAME_LIMIT_MAX}",
1695 );
1696 let actual = ValidationError {
1697 kind: ValidationErrorType::Username {
1698 len: Some(200),
1699 substring: None,
1700 },
1701 };
1702 assert_eq!(expected, actual.to_string());
1703
1704 let expected = "provided username cannot contain :".to_string();
1705 let actual = ValidationError {
1706 kind: ValidationErrorType::Username {
1707 len: None,
1708 substring: Some(":"),
1709 },
1710 };
1711 assert_eq!(expected, actual.to_string());
1712 }
1713
1714 #[test]
1715 fn audit_reason_length() {
1716 assert!(audit_reason("").is_ok());
1717 assert!(audit_reason("a").is_ok());
1718 assert!(audit_reason("a".repeat(500)).is_ok());
1719 assert!(audit_reason("a".repeat(512)).is_ok());
1720
1721 assert!(audit_reason("a".repeat(513)).is_err());
1722 }
1723
1724 #[test]
1725 fn auto_moderation_block_action_custom_message() {
1726 assert!(auto_moderation_block_action_custom_message_limit("").is_ok());
1727 assert!(auto_moderation_block_action_custom_message_limit("a".repeat(150)).is_ok());
1728 assert!(matches!(
1729 auto_moderation_block_action_custom_message_limit("a".repeat(151))
1730 .unwrap_err()
1731 .kind,
1732 ValidationErrorType::AutoModerationBlockActionCustomMessageLimit { len: 151 }
1733 ));
1734 }
1735
1736 #[test]
1737 fn auto_moderation_metadata_mention_total() {
1738 assert!(auto_moderation_metadata_mention_total_limit(0).is_ok());
1739 assert!(auto_moderation_metadata_mention_total_limit(1).is_ok());
1740 assert!(auto_moderation_metadata_mention_total_limit(50).is_ok());
1741
1742 assert!(auto_moderation_metadata_mention_total_limit(51).is_err());
1743 }
1744
1745 #[test]
1746 fn auto_moderation_metadata_keyword_filter_max() {
1747 let mut keywords = (0..1000).map(|_| "a").collect::<Vec<_>>();
1748
1749 assert!(auto_moderation_metadata_keyword_filter(&[] as &[&str]).is_ok());
1750 assert!(auto_moderation_metadata_keyword_filter(&["a".repeat(60)]).is_ok());
1751 assert!(auto_moderation_metadata_keyword_filter(&keywords).is_ok());
1752
1753 keywords.push("a");
1754
1755 assert!(auto_moderation_metadata_keyword_filter(&["a".repeat(61)]).is_err());
1756 assert!(auto_moderation_metadata_keyword_filter(&keywords).is_err());
1757 }
1758
1759 #[test]
1760 fn auto_moderation_metadata_keyword_allow_list_max() {
1761 let mut allow_list = (0..100).map(|_| "a").collect::<Vec<_>>();
1762
1763 assert!(auto_moderation_metadata_keyword_allow_list(&[] as &[&str]).is_ok());
1764 assert!(auto_moderation_metadata_keyword_allow_list(&["a".repeat(60)]).is_ok());
1765
1766 allow_list.push("a");
1767
1768 assert!(auto_moderation_metadata_keyword_allow_list(&["a".repeat(61)]).is_err());
1769 assert!(auto_moderation_metadata_keyword_allow_list(&allow_list).is_err());
1770 }
1771
1772 #[test]
1773 fn auto_moderation_metadata_preset_allow_list_max() {
1774 let mut allow_list = (0..1000).map(|_| "a").collect::<Vec<_>>();
1775
1776 assert!(auto_moderation_metadata_preset_allow_list(&[] as &[&str]).is_ok());
1777 assert!(auto_moderation_metadata_preset_allow_list(&["a".repeat(60)]).is_ok());
1778
1779 allow_list.push("a");
1780
1781 assert!(auto_moderation_metadata_preset_allow_list(&["a".repeat(61)]).is_err());
1782 assert!(auto_moderation_metadata_preset_allow_list(&allow_list).is_err());
1783 }
1784
1785 #[test]
1786 fn auto_moderation_metadata_regex_patterns_max() {
1787 let mut patterns = (0..10).map(|_| "a").collect::<Vec<_>>();
1788
1789 assert!(auto_moderation_metadata_regex_patterns(&[] as &[&str]).is_ok());
1790 assert!(auto_moderation_metadata_regex_patterns(&["a".repeat(260)]).is_ok());
1791
1792 patterns.push("a");
1793
1794 assert!(auto_moderation_metadata_regex_patterns(&["a".repeat(261)]).is_err());
1795 assert!(auto_moderation_metadata_regex_patterns(&patterns).is_err());
1796 }
1797
1798 #[test]
1799 fn auto_moderation_exempt_roles_max() {
1800 let mut roles = (1..=20).map(Id::new).collect::<Vec<_>>();
1801
1802 assert!(auto_moderation_exempt_roles(&[]).is_ok());
1803 assert!(auto_moderation_exempt_roles(&roles).is_ok());
1804
1805 roles.push(Id::new(21));
1806
1807 assert!(auto_moderation_exempt_roles(&roles).is_err());
1808 }
1809
1810 #[test]
1811 fn auto_moderation_exempt_channels_max() {
1812 let mut channels = (1..=50).map(Id::new).collect::<Vec<_>>();
1813
1814 assert!(auto_moderation_exempt_channels(&[]).is_ok());
1815 assert!(auto_moderation_exempt_channels(&channels).is_ok());
1816
1817 channels.push(Id::new(51));
1818
1819 assert!(auto_moderation_exempt_channels(&channels).is_err());
1820 }
1821
1822 #[test]
1823 fn auto_moderation_action_metadata_duration_seconds_max() {
1824 assert!(auto_moderation_action_metadata_duration_seconds(0).is_ok());
1825 assert!(auto_moderation_action_metadata_duration_seconds(1).is_ok());
1826 assert!(auto_moderation_action_metadata_duration_seconds(2_419_200).is_ok());
1827
1828 assert!(auto_moderation_action_metadata_duration_seconds(2_419_201).is_err());
1829 }
1830
1831 #[test]
1832 fn create_guild_ban_delete_message_seconds_max() {
1833 assert!(create_guild_ban_delete_message_seconds(0).is_ok());
1834 assert!(create_guild_ban_delete_message_seconds(1).is_ok());
1835 assert!(create_guild_ban_delete_message_seconds(604_800).is_ok());
1836
1837 assert!(create_guild_ban_delete_message_seconds(604_801).is_err());
1838 }
1839
1840 #[test]
1841 fn communication_disabled_until_max() {
1842 #[allow(clippy::cast_possible_wrap)]
1843 let now = SystemTime::now()
1844 .duration_since(UNIX_EPOCH)
1845 .unwrap()
1846 .as_secs() as i64;
1847
1848 let ok_timestamp =
1849 Timestamp::from_secs(now + COMMUNICATION_DISABLED_MAX_DURATION - 1000).unwrap();
1850 assert!(communication_disabled_until(ok_timestamp).is_ok());
1851
1852 let err_timestamp =
1853 Timestamp::from_secs(now + COMMUNICATION_DISABLED_MAX_DURATION + 1000).unwrap();
1854 assert!(communication_disabled_until(err_timestamp).is_err());
1855 }
1856
1857 #[test]
1858 fn get_channel_messages_limit_count() {
1859 assert!(get_channel_messages_limit(1).is_ok());
1860 assert!(get_channel_messages_limit(100).is_ok());
1861
1862 assert!(get_channel_messages_limit(0).is_err());
1863 assert!(get_channel_messages_limit(101).is_err());
1864 }
1865
1866 #[test]
1867 fn get_current_user_guilds_limit_count() {
1868 assert!(get_current_user_guilds_limit(1).is_ok());
1869 assert!(get_current_user_guilds_limit(200).is_ok());
1870
1871 assert!(get_current_user_guilds_limit(0).is_err());
1872 assert!(get_current_user_guilds_limit(201).is_err());
1873 }
1874
1875 #[test]
1876 fn get_guild_log_limit_count() {
1877 assert!(get_guild_audit_log_limit(1).is_ok());
1878 assert!(get_guild_audit_log_limit(100).is_ok());
1879
1880 assert!(get_guild_audit_log_limit(0).is_err());
1881 assert!(get_guild_audit_log_limit(101).is_err());
1882 }
1883
1884 #[test]
1885 fn get_guild_bans_limit_count() {
1886 assert!(get_guild_bans_limit(0).is_ok());
1887 assert!(get_guild_bans_limit(1000).is_ok());
1888
1889 assert!(get_guild_bans_limit(1001).is_err());
1890 }
1891
1892 #[test]
1893 fn get_guild_members_limit_count() {
1894 assert!(get_guild_members_limit(1).is_ok());
1895 assert!(get_guild_members_limit(1000).is_ok());
1896
1897 assert!(get_guild_members_limit(0).is_err());
1898 assert!(get_guild_members_limit(1001).is_err());
1899 }
1900
1901 #[test]
1902 fn get_reactions_limit_count() {
1903 assert!(get_reactions_limit(1).is_ok());
1904 assert!(get_reactions_limit(100).is_ok());
1905
1906 assert!(get_reactions_limit(0).is_err());
1907 assert!(get_reactions_limit(101).is_err());
1908 }
1909
1910 #[test]
1911 fn guild_name_length() {
1912 assert!(guild_name("aa").is_ok());
1913 assert!(guild_name("a".repeat(100)).is_ok());
1914
1915 assert!(guild_name("").is_err());
1916 assert!(guild_name("a").is_err());
1917 assert!(guild_name("a".repeat(101)).is_err());
1918 }
1919
1920 #[test]
1921 fn guild_prune_days_length() {
1922 assert!(guild_prune_days(1).is_ok());
1923 assert!(guild_prune_days(30).is_ok());
1924
1925 assert!(guild_prune_days(0).is_err());
1926 assert!(guild_prune_days(31).is_err());
1927 assert!(guild_prune_days(100).is_err());
1928 }
1929
1930 #[test]
1931 fn invite_max_age_length() {
1932 assert!(invite_max_age(0).is_ok());
1933 assert!(invite_max_age(86_400).is_ok());
1934 assert!(invite_max_age(604_800).is_ok());
1935
1936 assert!(invite_max_age(604_801).is_err());
1937 }
1938
1939 #[test]
1940 fn invite_max_uses_count() {
1941 assert!(invite_max_uses(0).is_ok());
1942 assert!(invite_max_uses(100).is_ok());
1943
1944 assert!(invite_max_uses(101).is_err());
1945 }
1946
1947 #[test]
1948 fn nickname_length() {
1949 assert!(nickname("a").is_ok());
1950 assert!(nickname("a".repeat(32)).is_ok());
1951
1952 assert!(nickname("").is_err());
1953 assert!(nickname("a".repeat(33)).is_err());
1954 }
1955
1956 #[test]
1957 fn scheduled_event_description_length() {
1958 assert!(scheduled_event_description("a").is_ok());
1959 assert!(scheduled_event_description("a".repeat(1000)).is_ok());
1960
1961 assert!(scheduled_event_description("").is_err());
1962 assert!(scheduled_event_description("a".repeat(1001)).is_err());
1963 }
1964
1965 #[test]
1966 fn scheduled_event_get_users_length() {
1967 assert!(scheduled_event_get_users(0).is_err());
1968 assert!(scheduled_event_get_users(101).is_err());
1969 assert!(scheduled_event_get_users(100).is_ok());
1970 assert!(scheduled_event_get_users(1).is_ok());
1971 }
1972
1973 #[test]
1974 fn scheduled_event_name_length() {
1975 assert!(scheduled_event_name("a").is_ok());
1976 assert!(scheduled_event_name("a".repeat(100)).is_ok());
1977
1978 assert!(scheduled_event_name("").is_err());
1979 assert!(scheduled_event_name("a".repeat(101)).is_err());
1980 }
1981
1982 #[test]
1983 fn search_guild_members_limit_count() {
1984 assert!(search_guild_members_limit(1).is_ok());
1985 assert!(search_guild_members_limit(1000).is_ok());
1986
1987 assert!(search_guild_members_limit(0).is_err());
1988 assert!(search_guild_members_limit(1001).is_err());
1989 }
1990
1991 #[test]
1992 fn stage_topic_length() {
1993 assert!(stage_topic("a").is_ok());
1994 assert!(stage_topic("a".repeat(120)).is_ok());
1995
1996 assert!(stage_topic("").is_err());
1997 assert!(stage_topic("a".repeat(121)).is_err());
1998 }
1999
2000 #[test]
2001 fn template_description_length() {
2002 assert!(template_description("").is_ok());
2003 assert!(template_description("a").is_ok());
2004 assert!(template_description("a".repeat(120)).is_ok());
2005
2006 assert!(template_description("a".repeat(121)).is_err());
2007 }
2008
2009 #[test]
2010 fn template_name_length() {
2011 assert!(template_name("a").is_ok());
2012 assert!(template_name("a".repeat(100)).is_ok());
2013
2014 assert!(template_name("").is_err());
2015 assert!(template_name("a".repeat(101)).is_err());
2016 }
2017
2018 #[test]
2019 fn username_length() {
2020 assert!(username("aa").is_ok());
2021 assert!(username("a".repeat(32)).is_ok());
2022
2023 assert!(username("a").is_err());
2024 assert!(username("a".repeat(33)).is_err());
2025
2026 assert!(username("no @ in username").is_err());
2027 assert!(username("no # in username").is_err());
2028 assert!(username("no : in username").is_err());
2029 assert!(username(r"no ``` in username").is_err());
2030 assert!(username("no discord in username").is_err());
2031 assert!(username("everyone").is_err());
2032 assert!(username("here").is_err());
2033 }
2034
2035 #[test]
2036 fn webhook_username_length() {
2037 assert!(webhook_username("aa").is_ok());
2038 assert!(webhook_username("a".repeat(80)).is_ok());
2039
2040 assert!(webhook_username("a").is_err());
2041 assert!(webhook_username("a".repeat(81)).is_err());
2042
2043 assert!(webhook_username("clyde").is_err());
2044 }
2045}