Experimental Discord bot written in Python
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

generalcog.py 3.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. from datetime import datetime, timedelta
  2. from discord import Member, Message
  3. from discord.ext import commands
  4. import re
  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):
  10. def __init__(self, bot: commands.Bot):
  11. super().__init__(bot)
  12. self.is_connected = False
  13. self.is_ready = False
  14. @commands.Cog.listener()
  15. async def on_connect(self):
  16. print('on_connect')
  17. self.is_connected = True
  18. @commands.Cog.listener()
  19. async def on_ready(self):
  20. print('on_ready')
  21. self.is_ready = True
  22. @commands.command(
  23. brief='Posts a test warning in the configured warning channel.'
  24. )
  25. @commands.has_permissions(ban_members=True)
  26. @commands.guild_only()
  27. async def testwarn(self, context):
  28. if Storage.get_config_value(context.guild, ConfigKey.WARNING_CHANNEL_ID) is None:
  29. await context.message.reply(
  30. f'{CONFIG["warning_emoji"]} No warning channel set!',
  31. mention_author=False)
  32. else:
  33. bm = BotMessage(
  34. context.guild,
  35. f'Test warning message (requested by {context.author.name})',
  36. type=BotMessage.TYPE_MOD_WARNING)
  37. await self.post_message(bm)
  38. @commands.command(
  39. brief='Simple test reply',
  40. )
  41. async def hello(self, context):
  42. await context.message.reply(
  43. f'Hey, {context.author.name}!',
  44. mention_author=False)
  45. @commands.command(
  46. brief='Shuts down the bot (admin only)',
  47. )
  48. @commands.has_permissions(administrator=True)
  49. @commands.guild_only()
  50. async def shutdown(self, context):
  51. await self.bot.close()
  52. @commands.command(
  53. brief='Mass deletes messages',
  54. description='Deletes recent messages by the given user. The age is ' +
  55. 'a duration, such as "30s", "5m", "1h30m". Messages far back in ' +
  56. 'the scrollback might not be deleted by this command.',
  57. usage='<user> <age>'
  58. )
  59. @commands.has_permissions(manage_messages=True)
  60. @commands.guild_only()
  61. async def deletemessages(self, context, user: str, age: str) -> None:
  62. member_id = self.__parse_member_id(user)
  63. if member_id is None:
  64. await context.message.reply(
  65. f'{CONFIG["failure_emoji"]} user must be a mention or numeric user id',
  66. mention_author=False)
  67. return
  68. try:
  69. age_delta: timedelta = parse_timedelta(age)
  70. except ValueError:
  71. await context.message.reply(
  72. f'{CONFIG["failure_emoji"]} age must be a timespan, like "30s", "10m", "1h30m"',
  73. mention_author=False)
  74. return
  75. cutoff: datetime = datetime.utcnow() - age_delta
  76. def predicate(message: Message) -> bool:
  77. return str(message.author.id) == member_id and message.created_at >= cutoff
  78. deleted_messages = []
  79. for channel in context.guild.text_channels:
  80. try:
  81. deleted_messages += await channel.purge(limit=100, check=predicate)
  82. except:
  83. # XXX: Sloppily glossing over access errors instead of checking access
  84. pass
  85. await context.message.reply(
  86. f'{CONFIG["success_emoji"]} Deleted {len(deleted_messages)} ' + \
  87. f'messages by <@!{member_id}> from the past {describe_timedelta(age_delta)}.',
  88. mention_author=False)
  89. def __parse_member_id(self, arg: str) -> str:
  90. p = re.compile('^<@!?([0-9]+)>$')
  91. m = p.match(arg)
  92. if m:
  93. return m.group(1)
  94. p = re.compile('^([0-9]+)$')
  95. m = p.match(arg)
  96. if m:
  97. return m.group(1)
  98. return None