Source

commands/hacker_utility/ask.js

  1. // Discord.js commando requirements
  2. const PermissionCommand = require('../../classes/permission-command');
  3. const { checkForRole, sendMessageToMember, } = require('../../discord-services');
  4. const { MessageEmbed, Collection, Message, } = require('discord.js');
  5. const BotGuildModel = require('../../classes/bot-guild');
  6. /**
  7. * The ask command tries to imitate a thread like functionality from slack. Users can ask questions, and then other
  8. * users can respond to the question, the responses are added on the same message embed, to keep the conversation on
  9. * the same message.
  10. * @category Commands
  11. * @subcategory Hacker-Utility
  12. * @extends PermissionCommand
  13. */
  14. class AskQuestion extends PermissionCommand {
  15. constructor(client) {
  16. super(client, {
  17. name: 'ask',
  18. group: 'hacker_utility',
  19. memberName: 'ask anonymous question with thread',
  20. description: 'Will send the question to the same channel, and add emoji collector for thread like support.',
  21. guildOnly: true,
  22. args: [
  23. {
  24. key: 'question',
  25. prompt: 'Question to ask',
  26. type: 'string',
  27. default: '',
  28. }
  29. ],
  30. });
  31. }
  32. /**
  33. * @param {BotGuildModel} botGuild
  34. * @param {Message} message
  35. * @param {Object} args
  36. * @param {String} args.question
  37. */
  38. async runCommand(botGuild, message, {question}) {
  39. // if question is blank let user know via DM and exit
  40. if (question === '') {
  41. sendMessageToMember(message.member, 'When using the !ask command, add your question on the same message!\n' +
  42. 'Like this: !ask This is a question');
  43. return;
  44. }
  45. // get current channel
  46. var curChannel = message.channel;
  47. // message embed to be used for question
  48. const qEmbed = new MessageEmbed()
  49. .setColor(botGuild.colors.questionEmbedColor)
  50. .setTitle('Question from ' + message.author.username)
  51. .setDescription(question);
  52. // send message and add emoji collector
  53. curChannel.send(qEmbed).then(async (msg) => {
  54. // list of users currently responding
  55. var onResponse = new Collection();
  56. msg.react('🇷'); // respond emoji
  57. msg.react('✅'); // answered emoji!
  58. msg.react('⏫'); // up vote emoji
  59. msg.react('⛔'); // delete emoji
  60. // filter and collector
  61. const emojiFilter = (reaction, user) => !user.bot && (reaction.emoji.name === '🇷' || reaction.emoji.name === '✅' || reaction.emoji.name === '⛔');
  62. const collector = msg.createReactionCollector(emojiFilter);
  63. collector.on('collect', async (reaction, user) => {
  64. // delete the reaction
  65. reaction.users.remove(user.id);
  66. // add response to question
  67. if (reaction.emoji.name === '🇷') {
  68. // make sure user is not already responding
  69. if (onResponse.has(user.id)) {
  70. return;
  71. } else {
  72. onResponse.set(user.id, user.username);
  73. }
  74. // prompt the response
  75. curChannel.send('<@' + user.id + '> Please send your response within 15 seconds! If you want to cancel write cancel.').then(prompt => {
  76. // filter and message await only one
  77. // only user who reacted this message will be able to add a reply to it
  78. curChannel.awaitMessages(m => m.author.id === user.id, {max: 1, time: 15000, errors: ['time']}).then((msgs) => {
  79. var response = msgs.first();
  80. // if cancel then do nothing
  81. if (response.content.toLowerCase() != 'cancel') {
  82. // if user has a mentor role, they get a special title
  83. if (checkForRole(response.member, botGuild.roleIDs.staffRole)) {
  84. msg.edit(msg.embeds[0].addField('🤓 ' + user.username + ' Responded:', response.content));
  85. } else {
  86. // add a field to the message embed with the response
  87. msg.edit(msg.embeds[0].addField(user.username + ' Responded:', response.content));
  88. }
  89. }
  90. // delete messages
  91. prompt.delete();
  92. response.delete();
  93. // remove user from on response list
  94. onResponse.delete(user.id);
  95. }).catch((msgs) => {
  96. prompt.delete();
  97. curChannel.send('<@' + user.id + '> Time is up! When you are ready to respond, emoji again!').then(msg => msg.delete({timeout: 2000}));
  98. // remove user from on response list
  99. onResponse.delete(user.id);
  100. });
  101. });
  102. }
  103. // check for check-mark emoji and only user who asked the question
  104. else if (reaction.emoji.name === '✅' && user.id === message.author.id) {
  105. // change color
  106. msg.embeds[0].setColor('#80c904');
  107. // change title and edit embed
  108. msg.edit(msg.embeds[0].setTitle('✅ ANSWERED ' + msg.embeds[0].title));
  109. }
  110. // remove emoji will remove the message
  111. else if (reaction.emoji.name === '⛔') {
  112. // check that user is staff
  113. if (checkForRole(msg.guild.member(user), botGuild.roleIDs.staffRole)) {
  114. msg.delete();
  115. } else {
  116. sendMessageToMember(user, 'Deleting a question is only available to staff!', true);
  117. }
  118. }
  119. });
  120. });
  121. }
  122. }
  123. module.exports = AskQuestion;