1pub mod permissions;
11
12mod command_type;
13mod option;
14
15pub use self::{
16 command_type::CommandType,
17 option::{
18 CommandOption, CommandOptionChoice, CommandOptionChoiceValue, CommandOptionType,
19 CommandOptionValue,
20 },
21};
22
23use crate::{
24 guild::Permissions,
25 id::{
26 Id,
27 marker::{ApplicationMarker, CommandMarker, CommandVersionMarker, GuildMarker},
28 },
29 oauth::ApplicationIntegrationType,
30};
31use serde::{Deserialize, Serialize};
32use std::collections::HashMap;
33
34use super::interaction::InteractionContextType;
35
36#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
44pub struct Command {
45 #[serde(skip_serializing_if = "Option::is_none")]
46 pub application_id: Option<Id<ApplicationMarker>>,
47 #[serde(skip_serializing_if = "Option::is_none")]
48 pub contexts: Option<Vec<InteractionContextType>>,
49 pub default_member_permissions: Option<Permissions>,
54 pub description: String,
61 #[serde(skip_serializing_if = "Option::is_none")]
67 pub description_localizations: Option<HashMap<String, String>>,
68 #[deprecated(note = "use contexts instead")]
73 #[serde(skip_serializing_if = "Option::is_none")]
74 pub dm_permission: Option<bool>,
75 #[serde(skip_serializing_if = "Option::is_none")]
77 pub guild_id: Option<Id<GuildMarker>>,
78 #[serde(skip_serializing_if = "Option::is_none")]
79 pub id: Option<Id<CommandMarker>>,
80 #[serde(skip_serializing_if = "Option::is_none")]
81 pub integration_types: Option<Vec<ApplicationIntegrationType>>,
82 #[serde(rename = "type")]
83 pub kind: CommandType,
84 pub name: String,
85 #[serde(skip_serializing_if = "Option::is_none")]
93 pub name_localizations: Option<HashMap<String, String>>,
94 #[serde(skip_serializing_if = "Option::is_none")]
98 pub nsfw: Option<bool>,
99 #[serde(default)]
100 pub options: Vec<CommandOption>,
101 pub version: Id<CommandVersionMarker>,
103}
104
105#[cfg(test)]
106mod tests {
107 use super::{
108 Command, CommandOption, CommandOptionChoice, CommandOptionChoiceValue, CommandOptionType,
109 CommandOptionValue, CommandType,
110 };
111 use crate::{channel::ChannelType, guild::Permissions, id::Id};
112 use serde_test::Token;
113 use std::collections::HashMap;
114
115 #[test]
116 #[allow(clippy::too_many_lines, deprecated)]
117 fn command_option_full() {
118 let value = Command {
119 application_id: Some(Id::new(100)),
120 contexts: None,
121 default_member_permissions: Some(Permissions::ADMINISTRATOR),
122 description: "this command is a test".into(),
123 description_localizations: Some(HashMap::from([(
124 "en-US".into(),
125 "this command is a test".into(),
126 )])),
127 dm_permission: Some(false),
128 guild_id: Some(Id::new(300)),
129 id: Some(Id::new(200)),
130 integration_types: None,
131 kind: CommandType::ChatInput,
132 name: "test command".into(),
133 name_localizations: Some(HashMap::from([("en-US".into(), "test command".into())])),
134 nsfw: None,
135 options: Vec::from([CommandOption {
136 autocomplete: None,
137 channel_types: None,
138 choices: None,
139 description: "sub command group desc".to_owned(),
140 description_localizations: None,
141 kind: CommandOptionType::SubCommandGroup,
142 max_length: None,
143 max_value: None,
144 min_length: None,
145 min_value: None,
146 name: "sub command group name".to_owned(),
147 name_localizations: None,
148 options: Some(Vec::from([CommandOption {
149 autocomplete: None,
150 channel_types: None,
151 choices: None,
152 description: "sub command desc".to_owned(),
153 description_localizations: None,
154 kind: CommandOptionType::SubCommand,
155 max_length: None,
156 max_value: None,
157 min_length: None,
158 min_value: None,
159 name: "sub command name".to_owned(),
160 name_localizations: None,
161 options: Some(Vec::from([
162 CommandOption {
163 autocomplete: None,
164 channel_types: None,
165 choices: None,
166 description: "attachment desc".to_owned(),
167 description_localizations: None,
168 kind: CommandOptionType::Attachment,
169 max_length: None,
170 max_value: None,
171 min_length: None,
172 min_value: None,
173 name: "attachment name".to_owned(),
174 name_localizations: None,
175 options: None,
176 file_types: None,
177 required: None,
178 },
179 CommandOption {
180 autocomplete: None,
181 channel_types: None,
182 choices: None,
183 description: "boolean desc".to_owned(),
184 description_localizations: None,
185 kind: CommandOptionType::Boolean,
186 max_length: None,
187 max_value: None,
188 min_length: None,
189 min_value: None,
190 name: "boolean name".to_owned(),
191 name_localizations: None,
192 options: None,
193 file_types: None,
194 required: Some(true),
195 },
196 CommandOption {
197 autocomplete: None,
198 channel_types: Some(Vec::new()),
199 choices: None,
200 description: "channel desc".to_owned(),
201 description_localizations: None,
202 kind: CommandOptionType::Channel,
203 max_length: None,
204 max_value: None,
205 min_length: None,
206 min_value: None,
207 name: "channel name".to_owned(),
208 name_localizations: None,
209 options: None,
210 file_types: None,
211 required: None,
212 },
213 CommandOption {
214 autocomplete: None,
215 channel_types: Some(Vec::from([ChannelType::GuildText])),
216 choices: None,
217 description: "channel desc".to_owned(),
218 description_localizations: None,
219 kind: CommandOptionType::Channel,
220 max_length: None,
221 max_value: None,
222 min_length: None,
223 min_value: None,
224 name: "channel name".to_owned(),
225 name_localizations: None,
226 options: None,
227 file_types: None,
228 required: None,
229 },
230 CommandOption {
231 autocomplete: Some(true),
232 channel_types: None,
233 choices: Some(Vec::new()),
234 description: "integer desc".to_owned(),
235 description_localizations: None,
236 kind: CommandOptionType::Integer,
237 max_length: None,
238 max_value: Some(CommandOptionValue::Integer(100)),
239 min_length: None,
240 min_value: Some(CommandOptionValue::Integer(0)),
241 name: "integer name".to_owned(),
242 name_localizations: None,
243 options: None,
244 file_types: None,
245 required: None,
246 },
247 CommandOption {
248 autocomplete: None,
249 channel_types: None,
250 choices: None,
251 description: "mentionable desc".to_owned(),
252 description_localizations: Some(HashMap::from([(
253 "en-GB".to_owned(),
254 "mentionable desc (but british)".to_owned(),
255 )])),
256 kind: CommandOptionType::Mentionable,
257 max_length: None,
258 max_value: None,
259 min_length: None,
260 min_value: None,
261 name: "mentionable name".to_owned(),
262 name_localizations: None,
263 options: None,
264 file_types: None,
265 required: None,
266 },
267 CommandOption {
268 autocomplete: Some(false),
269 channel_types: None,
270 choices: Some(Vec::from([CommandOptionChoice {
271 name: "number choice".to_owned(),
272 name_localizations: Some(HashMap::from([(
273 "en-US".to_owned(),
274 "number choice (but american)".to_owned(),
275 )])),
276 value: CommandOptionChoiceValue::Number(10.0),
277 }])),
278 description: "number desc".to_owned(),
279 description_localizations: None,
280 kind: CommandOptionType::Number,
281 max_length: None,
282 max_value: None,
283 min_length: None,
284 min_value: None,
285 name: "number name".to_owned(),
286 name_localizations: None,
287 options: None,
288 file_types: None,
289 required: None,
290 },
291 CommandOption {
292 autocomplete: None,
293 channel_types: None,
294 choices: None,
295 description: "role desc".to_owned(),
296 description_localizations: None,
297 kind: CommandOptionType::Role,
298 max_length: None,
299 max_value: None,
300 min_length: None,
301 min_value: None,
302 name: "role name".to_owned(),
303 name_localizations: Some(HashMap::from([(
304 "de-DE".to_owned(),
305 "role name (but german)".to_owned(),
306 )])),
307 options: None,
308 file_types: None,
309 required: None,
310 },
311 CommandOption {
312 autocomplete: None,
313 channel_types: None,
314 choices: None,
315 description: "string desc".to_owned(),
316 description_localizations: None,
317 kind: CommandOptionType::String,
318 max_length: Some(6000),
319 max_value: None,
320 min_length: Some(0),
321 min_value: None,
322 name: "string name".to_owned(),
323 name_localizations: None,
324 options: None,
325 file_types: None,
326 required: None,
327 },
328 ])),
329 file_types: None,
330 required: None,
331 }])),
332 file_types: None,
333 required: None,
334 }]),
335 version: Id::new(1),
336 };
337
338 serde_test::assert_tokens(
339 &value,
340 &[
341 Token::Struct {
342 name: "Command",
343 len: 12,
344 },
345 Token::Str("application_id"),
346 Token::Some,
347 Token::NewtypeStruct { name: "Id" },
348 Token::Str("100"),
349 Token::Str("default_member_permissions"),
350 Token::Some,
351 Token::Str("8"),
352 Token::Str("description"),
353 Token::Str("this command is a test"),
354 Token::Str("description_localizations"),
355 Token::Some,
356 Token::Map { len: Some(1) },
357 Token::Str("en-US"),
358 Token::Str("this command is a test"),
359 Token::MapEnd,
360 Token::Str("dm_permission"),
361 Token::Some,
362 Token::Bool(false),
363 Token::Str("guild_id"),
364 Token::Some,
365 Token::NewtypeStruct { name: "Id" },
366 Token::Str("300"),
367 Token::Str("id"),
368 Token::Some,
369 Token::NewtypeStruct { name: "Id" },
370 Token::Str("200"),
371 Token::Str("type"),
372 Token::U8(CommandType::ChatInput.into()),
373 Token::Str("name"),
374 Token::Str("test command"),
375 Token::Str("name_localizations"),
376 Token::Some,
377 Token::Map { len: Some(1) },
378 Token::Str("en-US"),
379 Token::Str("test command"),
380 Token::MapEnd,
381 Token::Str("options"),
382 Token::Seq { len: Some(1) },
383 Token::Struct {
384 name: "CommandOption",
385 len: 4,
386 },
387 Token::Str("description"),
388 Token::Str("sub command group desc"),
389 Token::Str("type"),
390 Token::U8(CommandOptionType::SubCommandGroup as u8),
391 Token::Str("name"),
392 Token::Str("sub command group name"),
393 Token::Str("options"),
394 Token::Some,
395 Token::Seq { len: Some(1) },
396 Token::Struct {
397 name: "CommandOption",
398 len: 4,
399 },
400 Token::Str("description"),
401 Token::Str("sub command desc"),
402 Token::Str("type"),
403 Token::U8(CommandOptionType::SubCommand as u8),
404 Token::Str("name"),
405 Token::Str("sub command name"),
406 Token::Str("options"),
407 Token::Some,
408 Token::Seq { len: Some(9) },
409 Token::Struct {
410 name: "CommandOption",
411 len: 3,
412 },
413 Token::Str("description"),
414 Token::Str("attachment desc"),
415 Token::Str("type"),
416 Token::U8(CommandOptionType::Attachment as u8),
417 Token::Str("name"),
418 Token::Str("attachment name"),
419 Token::StructEnd,
420 Token::Struct {
421 name: "CommandOption",
422 len: 4,
423 },
424 Token::Str("description"),
425 Token::Str("boolean desc"),
426 Token::Str("type"),
427 Token::U8(CommandOptionType::Boolean as u8),
428 Token::Str("name"),
429 Token::Str("boolean name"),
430 Token::Str("required"),
431 Token::Some,
432 Token::Bool(true),
433 Token::StructEnd,
434 Token::Struct {
435 name: "CommandOption",
436 len: 4,
437 },
438 Token::Str("channel_types"),
439 Token::Some,
440 Token::Seq { len: Some(0) },
441 Token::SeqEnd,
442 Token::Str("description"),
443 Token::Str("channel desc"),
444 Token::Str("type"),
445 Token::U8(CommandOptionType::Channel as u8),
446 Token::Str("name"),
447 Token::Str("channel name"),
448 Token::StructEnd,
449 Token::Struct {
450 name: "CommandOption",
451 len: 4,
452 },
453 Token::Str("channel_types"),
454 Token::Some,
455 Token::Seq { len: Some(1) },
456 Token::U8(ChannelType::GuildText.into()),
457 Token::SeqEnd,
458 Token::Str("description"),
459 Token::Str("channel desc"),
460 Token::Str("type"),
461 Token::U8(CommandOptionType::Channel as u8),
462 Token::Str("name"),
463 Token::Str("channel name"),
464 Token::StructEnd,
465 Token::Struct {
466 name: "CommandOption",
467 len: 7,
468 },
469 Token::Str("autocomplete"),
470 Token::Some,
471 Token::Bool(true),
472 Token::Str("choices"),
473 Token::Some,
474 Token::Seq { len: Some(0) },
475 Token::SeqEnd,
476 Token::Str("description"),
477 Token::Str("integer desc"),
478 Token::Str("type"),
479 Token::U8(CommandOptionType::Integer as u8),
480 Token::Str("max_value"),
481 Token::Some,
482 Token::I64(100),
483 Token::Str("min_value"),
484 Token::Some,
485 Token::I64(0),
486 Token::Str("name"),
487 Token::Str("integer name"),
488 Token::StructEnd,
489 Token::Struct {
490 name: "CommandOption",
491 len: 4,
492 },
493 Token::Str("description"),
494 Token::Str("mentionable desc"),
495 Token::Str("description_localizations"),
496 Token::Some,
497 Token::Map { len: Some(1) },
498 Token::Str("en-GB"),
499 Token::Str("mentionable desc (but british)"),
500 Token::MapEnd,
501 Token::Str("type"),
502 Token::U8(CommandOptionType::Mentionable as u8),
503 Token::Str("name"),
504 Token::Str("mentionable name"),
505 Token::StructEnd,
506 Token::Struct {
507 name: "CommandOption",
508 len: 5,
509 },
510 Token::Str("autocomplete"),
511 Token::Some,
512 Token::Bool(false),
513 Token::Str("choices"),
514 Token::Some,
515 Token::Seq { len: Some(1) },
516 Token::Struct {
517 name: "CommandOptionChoice",
518 len: 3,
519 },
520 Token::Str("name"),
521 Token::Str("number choice"),
522 Token::Str("name_localizations"),
523 Token::Some,
524 Token::Map { len: Some(1) },
525 Token::Str("en-US"),
526 Token::Str("number choice (but american)"),
527 Token::MapEnd,
528 Token::Str("value"),
529 Token::F64(10.0),
530 Token::StructEnd,
531 Token::SeqEnd,
532 Token::Str("description"),
533 Token::Str("number desc"),
534 Token::Str("type"),
535 Token::U8(CommandOptionType::Number as u8),
536 Token::Str("name"),
537 Token::Str("number name"),
538 Token::StructEnd,
539 Token::Struct {
540 name: "CommandOption",
541 len: 4,
542 },
543 Token::Str("description"),
544 Token::Str("role desc"),
545 Token::Str("type"),
546 Token::U8(CommandOptionType::Role as u8),
547 Token::Str("name"),
548 Token::Str("role name"),
549 Token::Str("name_localizations"),
550 Token::Some,
551 Token::Map { len: Some(1) },
552 Token::Str("de-DE"),
553 Token::Str("role name (but german)"),
554 Token::MapEnd,
555 Token::StructEnd,
556 Token::Struct {
557 name: "CommandOption",
558 len: 5,
559 },
560 Token::Str("description"),
561 Token::Str("string desc"),
562 Token::Str("type"),
563 Token::U8(CommandOptionType::String as u8),
564 Token::Str("max_length"),
565 Token::Some,
566 Token::U16(6000),
567 Token::Str("min_length"),
568 Token::Some,
569 Token::U16(0),
570 Token::Str("name"),
571 Token::Str("string name"),
572 Token::StructEnd,
573 Token::SeqEnd,
574 Token::StructEnd,
575 Token::SeqEnd,
576 Token::StructEnd,
577 Token::SeqEnd,
578 Token::Str("version"),
579 Token::NewtypeStruct { name: "Id" },
580 Token::Str("1"),
581 Token::StructEnd,
582 ],
583 );
584 }
585}