y21

message handler example

y21
Sep 5th, 2020
1,810
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import { Handler, MessageFilterCallback } from './handler';
  2.  
  3. // Structure for all questions
  4. // `description` is the actual "question" that the user responds to
  5. // `property` is the object key that will be set
  6. // `fn` is the filter function that's called to check whether a given message is valid
  7. // `errorMessage` is the error message that is sent if the given message does not match filter
  8. // `toPropertyValue` is an optional function that returns the value that will be assigned to data[property]
  9. interface Question {
  10.   description: string;
  11.   property: string;
  12.   fn: MessageFilterCallback;
  13.   errorMessage: string;
  14.   toPropertyValue?: (p: string) => string | number;
  15. }
  16.  
  17. // Command group for the command
  18. const commands = new discord.command.CommandGroup({
  19.   defaultPrefix: '..'
  20. });
  21.  
  22. const handler = new Handler();
  23.  
  24. // Regular expression for checking if input is a "color code" (e.g. #ff0000, #fff, ...)
  25. const COLOR_REGEX = new RegExp('^\\d+|#([A-F\\d]{3}|[A-F\\d]{6})$', 'i');
  26.  
  27. function isColorCode(str: string) {
  28.   return COLOR_REGEX.test(str);
  29. }
  30.  
  31. // Turns a "color code" into a number ("#ff0000" -> 16711680)
  32. function formatColor(str: string) {
  33.   return str.startsWith('#') ? parseInt(str.substr(1), 16) : Number(str);
  34. }
  35.  
  36. // This array includes all "questions"
  37. // See comments above `Question` interface to see what each field is for
  38. const questions: ReadonlyArray<Question> = [
  39.   // Question 1: embed title
  40.   // `fn` makes sure that the title won't exceed 256 characters
  41.   {
  42.     description: 'Embed title (max 256 characters)',
  43.     property: 'title',
  44.     fn: (handler, msg) => msg.content.length < 256,
  45.     errorMessage: 'Embed title must not be longer than 256 characters'
  46.   },
  47.  
  48.   // Question 2: embed description
  49.   // `fn` makes sure that the description won't exceed 1024 characters
  50.   {
  51.     description: 'Embed description (max 1024 characters)',
  52.     property: 'description',
  53.     fn: (handler, msg) => msg.content.length < 1024,
  54.     errorMessage: 'Embed description must not be longer than 1024 character'
  55.   },
  56.  
  57.   // Question 3: embed color
  58.   // `fn` makes sure that the color is a valid color code:
  59.   // #fff, #ffffff, 16777215
  60.   {
  61.     description: 'Embed color',
  62.     property: 'color',
  63.     fn: (handler, msg) => isColorCode(msg.content),
  64.     toPropertyValue: formatColor,
  65.     errorMessage:
  66.       "That doesn't look like a valid color code. Examples: #ff0000, #fff, #ffff00, 16777215"
  67.   }
  68. ];
  69.  
  70. commands.raw('embed', async (message) => {
  71.   // `question` will be the index used to get the current question
  72.   let question = 0;
  73.  
  74.   // `data` is the embed data that is sent after the user has answered all questions
  75.   // Using a null prototype object to keep it simple (won't inherit Object)
  76.   const data = Object.create(null);
  77.  
  78.   // Initial message
  79.   await message.reply(questions[question].description);
  80.  
  81.   await handler.createMessageHandler({
  82.     message,
  83.     async filter(handler, message) {
  84.       const currentQuestion = questions[question];
  85.  
  86.       // Forward all parameters to the current filter function
  87.       const result = await currentQuestion.fn(handler, message);
  88.  
  89.       // If the filter function returned false, respond with an error
  90.       if (!result) {
  91.         await message.reply(currentQuestion.errorMessage);
  92.         return false;
  93.       }
  94.  
  95.       // If everything is good, return true
  96.       return true;
  97.     },
  98.     async onMatch(handler, msg) {
  99.       // `onMatch` is called if the filter function returned true, which means that we can be sure that the given message is valid
  100.  
  101.       const currentQuestion = questions[question];
  102.  
  103.       // Assigns the formatted value to `property`, e.g. `data['title'] = msg.content` for the first question
  104.       // If `toPropertyValue` does not exist for this question, it defaults to the message content
  105.       data[currentQuestion.property] =
  106.         currentQuestion.toPropertyValue?.(msg.content) ?? msg.content;
  107.  
  108.       // Check if this was the last question
  109.       if (question >= questions.length - 1) {
  110.         // End handler by calling `done` on it
  111.         handler.done();
  112.  
  113.         // Finally respond with embed data
  114.         // `data` is an object that has all properties that were assigned previously (see line 103-104)
  115.         message.reply({ embed: data });
  116.         return;
  117.       }
  118.  
  119.       // Increment index (question) and send next question
  120.       question++;
  121.       await message.reply(questions[question].description);
  122.     }
  123.   });
  124. });
  125.  
RAW Paste Data