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

basecog.py 3.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. from discord import Guild, Message, PartialEmoji, RawReactionActionEvent, TextChannel
  2. from discord.ext import commands
  3. from datetime import timedelta
  4. from rscollections import AgeBoundDict
  5. from storage import ConfigKey, Storage
  6. import json
  7. class BaseCog(commands.Cog):
  8. def __init__(self, bot):
  9. self.bot = bot
  10. self.listened_mod_react_message_ids = AgeBoundDict(timedelta(minutes=5), lambda message_id, age : age)
  11. def listen_for_reactions_to(self, message: Message) -> None:
  12. self.listened_mod_react_message_ids[message.id] = message.created_at
  13. @commands.Cog.listener()
  14. async def on_raw_reaction_add(self, payload: RawReactionActionEvent):
  15. 'Event handler'
  16. if payload.user_id == self.bot.user.id:
  17. # Ignore bot's own reactions
  18. return
  19. member: Member = payload.member
  20. if member is None:
  21. return
  22. guild: Guild = self.bot.get_guild(payload.guild_id)
  23. if guild is None:
  24. # Possibly a DM
  25. return
  26. channel: GuildChannel = guild.get_channel(payload.channel_id)
  27. if channel is None:
  28. # Possibly a DM
  29. return
  30. message: Message = await channel.fetch_message(payload.message_id)
  31. if message is None:
  32. # Message deleted?
  33. return
  34. if message.author.id != self.bot.user.id:
  35. # Bot didn't author this
  36. return
  37. if not member.permissions_in(channel).ban_members:
  38. # Not a mod
  39. return
  40. if self.listened_mod_react_message_ids.get(message.id) is None:
  41. # Not a message we're listening for
  42. return
  43. await self.on_mod_react(message, payload.emoji)
  44. async def on_mod_react(self, message: Message, emoji: PartialEmoji) -> None:
  45. """
  46. Override point for getting a mod's emote on a bot message. Used to take
  47. action on a warning, such as banning an offending user. This event is
  48. only triggered for registered bot messages and reactions by members
  49. with the proper permissions.
  50. """
  51. pass
  52. @classmethod
  53. async def warn(cls, guild: Guild, message: str) -> Message:
  54. """
  55. Sends a warning message to the configured warning channel for the
  56. given guild. If no warning channel is configured no action is taken.
  57. Returns the Message if successful or None if not.
  58. """
  59. channel_id = Storage.get_config_value(guild, ConfigKey.WARNING_CHANNEL_ID)
  60. if channel_id is None:
  61. cls.guild_trace(guild, 'No warning channel set! No warning issued.')
  62. return None
  63. channel: TextChannel = guild.get_channel(channel_id)
  64. if channel is None:
  65. cls.guild_trace(guild, 'Configured warning channel does not exist!')
  66. return None
  67. mention: str = Storage.get_config_value(guild, ConfigKey.WARNING_MENTION)
  68. text: str = message
  69. if mention is not None:
  70. text = f'{mention} {text}'
  71. msg: Message = await channel.send(text)
  72. return msg
  73. @classmethod
  74. async def update_warn(cls, warn_message: Message, new_text: str) -> None:
  75. """
  76. Updates the text of a previously posted `warn`. Includes configured
  77. mentions if necessary.
  78. """
  79. text: str = new_text
  80. mention: str = Storage.get_config_value(
  81. warn_message.guild,
  82. ConfigKey.WARNING_MENTION)
  83. if mention is not None:
  84. text = f'{mention} {text}'
  85. await warn_message.edit(content=text)
  86. @classmethod
  87. def guild_trace(cls, guild: Guild, message: str) -> None:
  88. print(f'[guild {guild.id}|{guild.name}] {message}')