Experimental Discord bot written in Python
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

logcog.py 7.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. """
  2. Cog for detecting large numbers of guild joins in a short period of time.
  3. """
  4. import weakref
  5. from collections.abc import Sequence
  6. from datetime import datetime, timedelta
  7. from discord import Emoji, Guild, GuildSticker, Invite, Member, Message, RawMessageUpdateEvent, Role, Thread, User
  8. from discord.abc import GuildChannel
  9. from discord.ext import commands
  10. from typing import List, Union
  11. from config import CONFIG
  12. from rocketbot.cogs.basecog import BaseCog, BotMessage, BotMessageReaction, CogSetting
  13. from rocketbot.collections import AgeBoundList
  14. from rocketbot.storage import Storage
  15. class LogCog(BaseCog, name='Logging'):
  16. """
  17. Cog for logging notable events to a designated logging channel.
  18. """
  19. SETTING_ENABLED = CogSetting('enabled', bool,
  20. brief='logging',
  21. description='Whether this cog is enabled for a guild.')
  22. SETTING_EDITS_ENABLED = CogSetting('edits_enabled', bool,
  23. brief='post edits',
  24. description='Whether to log when users edit their posts.')
  25. SETTING_JOINS_ENABLED = CogSetting('joins_enabled', bool,
  26. brief='joins',
  27. description='Whether to log when new users join the server.')
  28. SETTING_LEAVES_ENABLED = CogSetting('leaves_enabled', bool,
  29. brief='leaves',
  30. description='Whether to log when users leave the server.')
  31. def __init__(self, bot):
  32. super().__init__(bot)
  33. self.add_setting(LogCog.SETTING_ENABLED)
  34. self.add_setting(LogCog.SETTING_EDITS_ENABLED)
  35. self.add_setting(LogCog.SETTING_JOINS_ENABLED)
  36. self.add_setting(LogCog.SETTING_LEAVES_ENABLED)
  37. @commands.group(
  38. brief='Manages event logging',
  39. )
  40. @commands.has_permissions(ban_members=True)
  41. @commands.guild_only()
  42. async def log(self, context: commands.Context):
  43. 'Logging command group'
  44. if context.invoked_subcommand is None:
  45. await context.send_help()
  46. # Events - Channels
  47. @commands.Cog.listener()
  48. async def on_guild_channel_delete(self, channel: GuildChannel) -> None:
  49. pass
  50. @commands.Cog.listener()
  51. async def on_guild_channel_create(self, channel: GuildChannel) -> None:
  52. pass
  53. @commands.Cog.listener()
  54. async def on_guild_channel_update(self, before: GuildChannel, after: GuildChannel) -> None:
  55. pass
  56. # Events - Guilds
  57. @commands.Cog.listener()
  58. async def on_guild_available(self, guild: Guild) -> None:
  59. pass
  60. @commands.Cog.listener()
  61. async def on_guild_unavailable(self, guild: Guild) -> None:
  62. pass
  63. @commands.Cog.listener()
  64. async def on_guild_update(self, before: Guild, after: Guild) -> None:
  65. pass
  66. @commands.Cog.listener()
  67. async def on_guild_emojis_update(self, guild: Guild, before: Sequence[Emoji], after: Sequence[Emoji]) -> None:
  68. pass
  69. @commands.Cog.listener()
  70. async def on_guild_stickers_update(self, guild: Guild, before: Sequence[GuildSticker], after: Sequence[GuildSticker]) -> None:
  71. pass
  72. @commands.Cog.listener()
  73. async def on_invite_create(self, invite: Invite) -> None:
  74. pass
  75. @commands.Cog.listener()
  76. async def on_invite_delete(self, invite: Invite) -> None:
  77. pass
  78. # Events - Members
  79. @commands.Cog.listener()
  80. async def on_member_join(self, member: Member) -> None:
  81. pass
  82. @commands.Cog.listener()
  83. async def on_member_remove(self, member: Member) -> None:
  84. pass
  85. @commands.Cog.listener()
  86. async def on_member_update(self, before: Member, after: Member) -> None:
  87. pass
  88. @commands.Cog.listener()
  89. async def on_user_update(self, before: User, after: User) -> None:
  90. pass
  91. @commands.Cog.listener()
  92. async def on_member_ban(self, user: Union[User, Member]) -> None:
  93. pass
  94. @commands.Cog.listener()
  95. async def on_member_unban(self, guild: Guild, user: Union[User, Member]) -> None:
  96. pass
  97. # Events - Messages
  98. @commands.Cog.listener()
  99. async def on_message(self, message: Message):
  100. print(f"Saw message \"{message.content}\"")
  101. @commands.Cog.listener()
  102. async def on_message_edit(self, before: Message, after: Message) -> None:
  103. print(f"Message \"{before.content}\" changed to \"{after.content}\"")
  104. @commands.Cog.listener()
  105. async def on_raw_message_edit(self, payload: RawMessageUpdateEvent) -> None:
  106. if payload.cached_message:
  107. print("Edited message is cached")
  108. return # already handled by on_message_edit
  109. print(f"Fetching guild {payload.guild_id}")
  110. guild = await self.bot.fetch_guild(payload.guild_id)
  111. if not guild:
  112. print(f"Couldn't fetch edited message guild {payload.guild_id}")
  113. return
  114. print(f"Fetching channel {payload.channel_id}")
  115. channel = await guild.fetch_channel(payload.channel_id)
  116. if not channel:
  117. print(f"Couldn't fetch edited message channel {payload.channel_id}")
  118. return
  119. print(f"Fetching message {payload.message_id}")
  120. message = await channel.fetch_message(payload.message_id)
  121. if not message:
  122. print(f"Couldn't fetch edited message {payload.message_id}")
  123. return
  124. print(f"Message was edited, but I don't have the old version. Current version is \"{message.content}\"")
  125. @commands.Cog.listener()
  126. async def on_message_delete(self, message: Message) -> None:
  127. print(f"Message deleted \"{message.content}\"")
  128. @commands.Cog.listener()
  129. async def on_bulk_message_delete(self, messages: List[Message]) -> None:
  130. pass
  131. # Events - Roles
  132. @commands.Cog.listener()
  133. async def on_guild_role_create(self, role: Role) -> None:
  134. pass
  135. @commands.Cog.listener()
  136. async def on_guild_role_delete(self, role: Role) -> None:
  137. pass
  138. @commands.Cog.listener()
  139. async def on_guild_role_update(self, before: Role, after: Role) -> None:
  140. pass
  141. # Events - Threads
  142. @commands.Cog.listener()
  143. async def on_thread_create(self, thread: Thread) -> None:
  144. pass
  145. @commands.Cog.listener()
  146. async def on_thread_update(self, before: Thread, after: Thread) -> None:
  147. pass
  148. @commands.Cog.listener()
  149. async def on_thread_delete(self, thread: Thread) -> None:
  150. pass
  151. # ------------------------------------------------------------------------
  152. def remove_me():
  153. pass
  154. # @commands.Cog.listener()
  155. # async def on_member_join(self, member: Member) -> None:
  156. # 'Event handler'
  157. # guild: Guild = member.guild
  158. # if not self.get_guild_setting(guild, self.SETTING_ENABLED):
  159. # return
  160. # min_count = self.get_guild_setting(guild, self.SETTING_JOIN_COUNT)
  161. # seconds = self.get_guild_setting(guild, self.SETTING_JOIN_TIME)
  162. # timespan: timedelta = timedelta(seconds=seconds)
  163. # last_raid: JoinRaidContext = Storage.get_state_value(guild, self.STATE_KEY_LAST_RAID)
  164. # recent_joins: AgeBoundList = Storage.get_state_value(guild, self.STATE_KEY_RECENT_JOINS)
  165. # if recent_joins is None:
  166. # recent_joins = AgeBoundList(timespan, lambda i, member : member.joined_at)
  167. # Storage.set_state_value(guild, self.STATE_KEY_RECENT_JOINS, recent_joins)
  168. # if last_raid:
  169. # if member.joined_at - last_raid.last_join_time() > timespan:
  170. # # Last raid is over
  171. # Storage.set_state_value(guild, self.STATE_KEY_LAST_RAID, None)
  172. # recent_joins.append(member)
  173. # return
  174. # # Add join to existing raid
  175. # last_raid.join_members.append(member)
  176. # self.record_warning(member)
  177. # if len(last_raid.banned_members) > 0:
  178. # self.log(guild, f'Banning as part of last join raid: {member.name}')
  179. # await member.ban(
  180. # reason='Rocketbot: Part of join raid.',
  181. # delete_message_days=0)
  182. # last_raid.banned_members.add(member)
  183. # elif len(last_raid.kicked_members) > 0:
  184. # self.log(guild, f'Kicking as part of last join raid: {member.name}')
  185. # await member.kick(
  186. # reason='Rocketbot: Part of join raid.')
  187. # last_raid.kicked_members.add(member)
  188. # await self.__update_warning_message(last_raid)
  189. # else:
  190. # # Add join to the general, non-raid recent join list
  191. # recent_joins.append(member)
  192. # if len(recent_joins) >= min_count:
  193. # self.log(guild, '\u0007Join raid detected')
  194. # last_raid = JoinRaidContext(recent_joins)
  195. # Storage.set_state_value(guild, self.STATE_KEY_LAST_RAID, last_raid)
  196. # recent_joins.clear()
  197. # msg = BotMessage(guild,
  198. # text='',
  199. # type=BotMessage.TYPE_MOD_WARNING,
  200. # context=last_raid)
  201. # self.record_warnings(recent_joins)
  202. # last_raid.warning_message_ref = weakref.ref(msg)
  203. # await self.__update_warning_message(last_raid)
  204. # await self.post_message(msg)