y21

Untitled

y21
May 9th, 2020
1,930
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // Pylon does not expose any commandgroup properties like prefix, so we store it in a variable
  2. const commandGroupOptions: discord.command.ICommandGroupOptions = {
  3.   defaultPrefix: '..'
  4. };
  5.  
  6. const responses = {
  7.   yes: ['yes', 'y'],
  8.   no: ['no', 'n']
  9. };
  10.  
  11. const descriptions = {
  12.   ban: 'Bans a mentioned user',
  13.   kick: 'Kicks a mentioned user',
  14.   unban: 'Unbans a mentioned user',
  15.   softban: 'Bans and unbans a user (deletes messages sent in the past 7 days)',
  16.   slowmode: 'Sets the slowmode for a channel'
  17. };
  18.  
  19. const cmdgroup = new discord.command.CommandGroup(commandGroupOptions);
  20.  
  21. const enum ModAction {
  22.   BAN = 'ban',
  23.   KICK = 'kick',
  24.   SOFTBAN = 'softban',
  25.   UNBAN = 'unban'
  26. }
  27.  
  28. interface ModEntry {
  29.   userId: string;
  30.   messageId: string;
  31.   targetId: string;
  32.   action: ModAction;
  33.   triggeredAt: number;
  34.   requiresGuildMemberObject: boolean; // commands like ban require a guild member object, while unban does not
  35. }
  36.  
  37. // Used in our slowmode command
  38. const timeSuffix: {
  39.   [index: string]: number;
  40. } = {
  41.   s: 1,
  42.   m: 60,
  43.   h: 3600
  44. };
  45.  
  46. // How long to wait for confirmation
  47. const ttl = 60000;
  48.  
  49. const modKv = new pylon.KVNamespace('modResponses');
  50.  
  51. async function handleModCommand(
  52.   message: discord.GuildMemberMessage,
  53.   userId: string,
  54.   action: ModAction,
  55.   requiresGuildMemberObject: boolean
  56. ) {
  57.   const user = await discord.getUser(userId);
  58.   if (!user) return message.reply('Could not find user');
  59.  
  60.   const confirmMsg = await message.reply(
  61.     `Do you really want to ${action} __${user.getTag()}__? Reply with __y__es or __n__o within the next ${ttl /
  62.       1000} seconds.`
  63.   );
  64.  
  65.   const entry: ModEntry = {
  66.     action,
  67.     messageId: confirmMsg.id,
  68.     userId: message.author.id,
  69.     targetId: userId,
  70.     triggeredAt: Date.now(),
  71.     requiresGuildMemberObject
  72.   };
  73.  
  74.   await modKv.put(message.author.id, <any>entry, { ttl });
  75. }
  76.  
  77. // Commands
  78. cmdgroup.on(
  79.   {
  80.     name: 'ban',
  81.     filters: discord.command.filters.canBanMembers(),
  82.     description: descriptions.ban
  83.   },
  84.   (ctx) => ({
  85.     member: ctx.guildMember()
  86.   }),
  87.   async (message, { member }) =>
  88.     await handleModCommand(message, member.user.id, ModAction.BAN, true)
  89. );
  90.  
  91. cmdgroup.on(
  92.   {
  93.     name: 'kick',
  94.     filters: discord.command.filters.canKickMembers(),
  95.     description: descriptions.kick
  96.   },
  97.   (ctx) => ({
  98.     member: ctx.guildMember()
  99.   }),
  100.   async (message, { member }) =>
  101.     await handleModCommand(message, member.user.id, ModAction.KICK, true)
  102. );
  103.  
  104. cmdgroup.on(
  105.   {
  106.     name: 'softban',
  107.     filters: discord.command.filters.canBanMembers(),
  108.     description: descriptions.softban
  109.   },
  110.   (ctx) => ({
  111.     member: ctx.guildMember()
  112.   }),
  113.   async (message, { member }) =>
  114.     await handleModCommand(message, member.user.id, ModAction.SOFTBAN, true)
  115. );
  116.  
  117. cmdgroup.on(
  118.   {
  119.     name: 'unban',
  120.     filters: discord.command.filters.canBanMembers(),
  121.     description: descriptions.unban
  122.   },
  123.   (ctx) => ({ userId: ctx.string() }),
  124.   async (message, { userId }) =>
  125.     await handleModCommand(message, userId, ModAction.UNBAN, false)
  126. );
  127.  
  128. cmdgroup.raw('help', async (message) => {
  129.   await message.reply(
  130.     new discord.Embed().setFields(
  131.       Object.entries(descriptions).map(
  132.         ([command, desc]): discord.Embed.IEmbedField => ({
  133.           name: command ?? '-',
  134.           value: desc ?? 'Description not found'
  135.         })
  136.       )
  137.     )
  138.   );
  139. });
  140.  
  141. cmdgroup.on(
  142.   {
  143.     name: 'slowmode',
  144.     filters: discord.command.filters.canManageChannels(),
  145.     description: descriptions.slowmode
  146.   },
  147.   (ctx) => ({ time: ctx.string() }),
  148.   async (message, { time }) => {
  149.     const [, num, format] = time.match(/(\d+)([smh])/) ?? [];
  150.     if (!num || !format)
  151.       return message.reply(
  152.         `Invalid format! Example: ${commandGroupOptions.defaultPrefix}slowmode 10s`
  153.       );
  154.  
  155.     const channel = await message.getChannel();
  156.     await channel.edit({
  157.       rateLimitPerUser: parseInt(num, 10) * timeSuffix[format]
  158.     });
  159.  
  160.     await message.reply(`Updated slowmode for channel ${channel.toMention()}`);
  161.   }
  162. );
  163.  
  164. // Handlers
  165. discord.on(discord.Event.MESSAGE_CREATE, async (message) => {
  166.   if (
  167.     !message.author ||
  168.     message.author.bot ||
  169.     !(message instanceof discord.GuildMemberMessage)
  170.   )
  171.     return;
  172.  
  173.   const entry = <ModEntry>(<unknown>await modKv.get(message.author.id));
  174.   if (!entry) return;
  175.  
  176.   const guild = await message.getGuild();
  177.   const member = await guild.getMember(entry.targetId);
  178.   const user = <discord.User>(
  179.     (member?.user || (await discord.getUser(entry.targetId)))
  180.   );
  181.  
  182.   if (responses.yes.some((v) => message.content.toLowerCase() === v)) {
  183.     const reason = `Responsible moderator: ${message.author.getTag()}`;
  184.  
  185.     const processingMsg = await message.reply(
  186.       `Performing action ${entry.action} on ${user.getTag()}`
  187.     );
  188.     try {
  189.       switch (entry.action) {
  190.         case ModAction.BAN:
  191.           await member?.ban({ reason });
  192.           break;
  193.         case ModAction.KICK:
  194.           await member?.kick();
  195.           break;
  196.         case ModAction.SOFTBAN:
  197.           await member?.ban({
  198.             reason,
  199.             deleteMessageDays: 7
  200.           });
  201.           await guild.deleteBan(entry.targetId);
  202.           break;
  203.         case ModAction.UNBAN:
  204.           guild.deleteBan(entry.targetId);
  205.           break;
  206.       }
  207.  
  208.       await processingMsg.edit(
  209.         `OK! Executed action ${entry.action} on user ${(
  210.           member?.user ?? user
  211.         ).getTag()}`
  212.       );
  213.     } catch (e) {
  214.       await processingMsg.edit(`Action failed: ${e.message}`);
  215.     }
  216.  
  217.     await modKv.delete(message.author.id);
  218.   } else if (responses.no.some((v) => message.content.toLowerCase() === v)) {
  219.     await message.reply(`Cancelled ${entry.action} for ${user.getTag()}`);
  220.     await modKv.delete(message.author.id);
  221.   }
  222. });
RAW Paste Data