Experimental Discord bot written in Python
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

generalcog.py 4.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import re
  2. from datetime import datetime, timedelta
  3. from discord import Message
  4. from discord.ext import commands
  5. from cogs.basecog import BaseCog, BotMessage
  6. from config import CONFIG
  7. from rbutils import parse_timedelta, describe_timedelta
  8. from storage import ConfigKey, Storage
  9. class GeneralCog(BaseCog, name='General'):
  10. """
  11. Cog for handling high-level bot functionality and commands. Should be the
  12. first cog added to the bot.
  13. """
  14. def __init__(self, bot: commands.Bot):
  15. super().__init__(bot)
  16. self.is_connected = False
  17. self.is_ready = False
  18. @commands.Cog.listener()
  19. async def on_connect(self):
  20. 'Event handler'
  21. print('on_connect')
  22. self.is_connected = True
  23. @commands.Cog.listener()
  24. async def on_ready(self):
  25. 'Event handler'
  26. print('on_ready')
  27. self.is_ready = True
  28. @commands.command(
  29. brief='Posts a test warning',
  30. description='Tests whether a warning channel is configured for this ' + \
  31. 'guild by posting a test warning. If a mod mention is ' + \
  32. 'configured, that user/role will be tagged in the test warning.',
  33. )
  34. @commands.has_permissions(ban_members=True)
  35. @commands.guild_only()
  36. async def testwarn(self, context):
  37. 'Command handler'
  38. if Storage.get_config_value(context.guild, ConfigKey.WARNING_CHANNEL_ID) is None:
  39. await context.message.reply(
  40. f'{CONFIG["warning_emoji"]} No warning channel set!',
  41. mention_author=False)
  42. else:
  43. bm = BotMessage(
  44. context.guild,
  45. f'Test warning message (requested by {context.author.name})',
  46. type=BotMessage.TYPE_MOD_WARNING)
  47. await self.post_message(bm)
  48. @commands.command(
  49. brief='Simple test reply',
  50. description='Replies to the command message. Useful to ensure the ' + \
  51. 'bot is working properly.',
  52. )
  53. async def hello(self, context):
  54. 'Command handler'
  55. await context.message.reply(
  56. f'Hey, {context.author.name}!',
  57. mention_author=False)
  58. @commands.command(
  59. brief='Shuts down the bot',
  60. description='Causes the bot script to terminate. Only usable by a ' + \
  61. 'user with server admin permissions.',
  62. )
  63. @commands.has_permissions(administrator=True)
  64. @commands.guild_only()
  65. async def shutdown(self, context: commands.Context):
  66. 'Command handler'
  67. await context.message.add_reaction('👋')
  68. await self.bot.close()
  69. @commands.command(
  70. brief='Mass deletes messages',
  71. description='Deletes recent messages by the given user. The user ' +
  72. 'can be either an @ mention or a numeric user ID. The age is ' +
  73. 'a duration, such as "30s", "5m", "1h30m". Only the most ' +
  74. 'recent 100 messages in each channel are searched.',
  75. usage='<user:id|mention> <age:timespan>'
  76. )
  77. @commands.has_permissions(manage_messages=True)
  78. @commands.guild_only()
  79. async def deletemessages(self, context, user: str, age: str) -> None:
  80. 'Command handler'
  81. member_id = self.__parse_member_id(user)
  82. if member_id is None:
  83. await context.message.reply(
  84. f'{CONFIG["failure_emoji"]} user must be a mention or numeric user id',
  85. mention_author=False)
  86. return
  87. try:
  88. age_delta: timedelta = parse_timedelta(age)
  89. except ValueError:
  90. await context.message.reply(
  91. f'{CONFIG["failure_emoji"]} age must be a timespan, like "30s", "10m", "1h30m"',
  92. mention_author=False)
  93. return
  94. cutoff: datetime = datetime.utcnow() - age_delta
  95. def predicate(message: Message) -> bool:
  96. return str(message.author.id) == member_id and message.created_at >= cutoff
  97. deleted_messages = []
  98. for channel in context.guild.text_channels:
  99. try:
  100. deleted_messages += await channel.purge(limit=100, check=predicate)
  101. except:
  102. # XXX: Sloppily glossing over access errors instead of checking access
  103. pass
  104. await context.message.reply(
  105. f'{CONFIG["success_emoji"]} Deleted {len(deleted_messages)} ' + \
  106. f'messages by <@!{member_id}> from the past {describe_timedelta(age_delta)}.',
  107. mention_author=False)
  108. def __parse_member_id(self, arg: str) -> str:
  109. p = re.compile('^<@!?([0-9]+)>$')
  110. m = p.match(arg)
  111. if m:
  112. return m.group(1)
  113. p = re.compile('^([0-9]+)$')
  114. m = p.match(arg)
  115. if m:
  116. return m.group(1)
  117. return None