[Mod] Added [p]cleanup bot, [p]cleanup self (#466)

`[p]cleanup bot` deletes user's command messages and bot's messages
`[p]cleanup self` deletes bot's messages
This commit is contained in:
Twentysix 2016-11-14 15:10:36 +01:00 committed by GitHub
commit 26ab7f2c45

View File

@ -6,6 +6,7 @@ from __main__ import send_cmd_help, settings
from collections import deque, defaultdict from collections import deque, defaultdict
from cogs.utils.chat_formatting import escape_mass_mentions, box from cogs.utils.chat_formatting import escape_mass_mentions, box
import os import os
import re
import logging import logging
import asyncio import asyncio
@ -398,14 +399,10 @@ class Mod:
dataIO.save_json("data/mod/perms_cache.json", self._perms_cache) dataIO.save_json("data/mod/perms_cache.json", self._perms_cache)
await self.bot.say("User has been unmuted in this server.") await self.bot.say("User has been unmuted in this server.")
@commands.group(pass_context=True, no_pm=True) @commands.group(pass_context=True)
@checks.mod_or_permissions(manage_messages=True) @checks.mod_or_permissions(manage_messages=True)
async def cleanup(self, ctx): async def cleanup(self, ctx):
"""Deletes messages. """Deletes messages."""
cleanup messages [number]
cleanup user [name/mention] [number]
cleanup text \"Text here\" [number]"""
if ctx.invoked_subcommand is None: if ctx.invoked_subcommand is None:
await send_cmd_help(ctx) await send_cmd_help(ctx)
@ -492,7 +489,7 @@ class Mod:
while tries_left and len(to_delete) - 1 < number: while tries_left and len(to_delete) - 1 < number:
async for message in self.bot.logs_from(channel, limit=100, async for message in self.bot.logs_from(channel, limit=100,
before=tmp): before=tmp):
if len(to_delete) -1 < number and check(message): if len(to_delete) - 1 < number and check(message):
to_delete.append(message) to_delete.append(message)
tmp = message tmp = message
tries_left -= 1 tries_left -= 1
@ -514,6 +511,8 @@ class Mod:
To get a message id, enable developer mode in Discord's To get a message id, enable developer mode in Discord's
settings, 'appearance' tab. Then right click a message settings, 'appearance' tab. Then right click a message
and copy its id. and copy its id.
This command only works on bots running as bot accounts.
""" """
channel = ctx.message.channel channel = ctx.message.channel
@ -522,6 +521,11 @@ class Mod:
is_bot = self.bot.user.bot is_bot = self.bot.user.bot
has_permissions = channel.permissions_for(server.me).manage_messages has_permissions = channel.permissions_for(server.me).manage_messages
if not is_bot:
await self.bot.say("This command can only be used on bots with "
"bot accounts.")
return
to_delete = [] to_delete = []
after = await self.bot.get_message(channel, message_id) after = await self.bot.get_message(channel, message_id)
@ -541,10 +545,7 @@ class Mod:
"".format(author.name, author.id, "".format(author.name, author.id,
len(to_delete), channel.name)) len(to_delete), channel.name))
if is_bot: await self.mass_purge(to_delete)
await self.mass_purge(to_delete)
else:
await self.slow_deletion(to_delete)
@cleanup.command(pass_context=True, no_pm=True) @cleanup.command(pass_context=True, no_pm=True)
async def messages(self, ctx, number: int): async def messages(self, ctx, number: int):
@ -577,6 +578,139 @@ class Mod:
else: else:
await self.slow_deletion(to_delete) await self.slow_deletion(to_delete)
@cleanup.command(pass_context=True, no_pm=True, name='bot')
async def cleanup_bot(self, ctx, number: int):
"""Cleans up command messages and messages from the bot"""
channel = ctx.message.channel
author = ctx.message.author
server = channel.server
is_bot = self.bot.user.bot
has_permissions = channel.permissions_for(server.me).manage_messages
prefixes = self.bot.command_prefix
if isinstance(prefixes, str):
prefixes = [prefixes]
elif callable(prefixes):
if asyncio.iscoroutine(prefixes):
await self.bot.say('Coroutine prefixes not yet implemented.')
return
prefixes = prefixes(self.bot, ctx.message)
# In case some idiot sets a null prefix
if '' in prefixes:
prefixes.pop('')
def check(m):
if m.author.id == self.bot.user.id:
return True
elif m == ctx.message:
return True
p = discord.utils.find(m.content.startswith, prefixes)
if p and len(p) > 0:
return m.content[len(p):].startswith(tuple(self.bot.commands))
return False
to_delete = [ctx.message]
if not has_permissions:
await self.bot.say("I'm not allowed to delete messages.")
return
tries_left = 5
tmp = ctx.message
while tries_left and len(to_delete) - 1 < number:
async for message in self.bot.logs_from(channel, limit=100,
before=tmp):
if len(to_delete) - 1 < number and check(message):
to_delete.append(message)
tmp = message
tries_left -= 1
logger.info("{}({}) deleted {} "
" command messages in channel {}"
"".format(author.name, author.id, len(to_delete),
channel.name))
if is_bot:
await self.mass_purge(to_delete)
else:
await self.slow_deletion(to_delete)
@cleanup.command(pass_context=True, name='self')
async def cleanup_self(self, ctx, number: int, match_pattern: str = None):
"""Cleans up messages owned by the bot.
By default, all messages are cleaned. If a third argument is specified,
it is used for pattern matching: If it begins with r( and ends with ),
then it is interpreted as a regex, and messages that match it are
deleted. Otherwise, it is used in a simple substring test.
Some helpful regex flags to include in your pattern:
Dots match newlines: (?s); Ignore case: (?i); Both: (?si)
"""
channel = ctx.message.channel
author = ctx.message.author
is_bot = self.bot.user.bot
# You can always delete your own messages, this is needed to purge
can_mass_purge = False
if type(author) is discord.Member:
me = channel.server.me
can_mass_purge = channel.permissions_for(me).manage_messages
use_re = (match_pattern and match_pattern.startswith('r(') and
match_pattern.endswith(')'))
if use_re:
match_pattern = match_pattern[1:] # strip 'r'
match_re = re.compile(match_pattern)
def content_match(c):
return bool(match_re.match(c))
elif match_pattern:
def content_match(c):
return match_pattern in c
else:
def content_match(_):
return True
def check(m):
if m.author.id != self.bot.user.id:
return False
elif content_match(m.content):
return True
return False
to_delete = []
tries_left = 5
tmp = ctx.message
while tries_left and len(to_delete) < number:
async for message in self.bot.logs_from(channel, limit=100,
before=tmp):
if len(to_delete) < number and check(message):
to_delete.append(message)
tmp = message
tries_left -= 1
if channel.name:
channel_name = 'channel ' + channel.name
else:
channel_name = str(channel)
logger.info("{}({}) deleted {} messages "
"sent by the bot in {}"
"".format(author.name, author.id, len(to_delete),
channel_name))
if is_bot and can_mass_purge:
await self.mass_purge(to_delete)
else:
await self.slow_deletion(to_delete)
@commands.command(pass_context=True) @commands.command(pass_context=True)
@checks.mod_or_permissions(manage_messages=True) @checks.mod_or_permissions(manage_messages=True)
async def reason(self, ctx, case, *, reason : str=""): async def reason(self, ctx, case, *, reason : str=""):
@ -613,7 +747,6 @@ class Mod:
else: else:
await self.bot.say("Case #{} updated.".format(case)) await self.bot.say("Case #{} updated.".format(case))
@commands.group(pass_context=True) @commands.group(pass_context=True)
@checks.is_owner() @checks.is_owner()
async def blacklist(self, ctx): async def blacklist(self, ctx):
@ -938,7 +1071,6 @@ class Mod:
await self.bot.delete_message(message) await self.bot.delete_message(message)
except: except:
pass pass
await asyncio.sleep(1.5)
def is_mod_or_superior(self, message): def is_mod_or_superior(self, message):
user = message.author user = message.author
@ -1057,7 +1189,7 @@ class Mod:
self.cache[author].append(message) self.cache[author].append(message)
msgs = self.cache[author] msgs = self.cache[author]
if len(msgs) == 3 and \ if len(msgs) == 3 and \
msgs[0].content == msgs[1].content == msgs[2].content: msgs[0].content == msgs[1].content == msgs[2].content:
if any([m.attachments for m in msgs]): if any([m.attachments for m in msgs]):
return False return False
try: try:
@ -1146,6 +1278,7 @@ class Mod:
empty = [p for p in iter(discord.PermissionOverwrite())] empty = [p for p in iter(discord.PermissionOverwrite())]
return original == empty return original == empty
def check_folders(): def check_folders():
folders = ("data", "data/mod/") folders = ("data", "data/mod/")
for folder in folders: for folder in folders:
@ -1174,6 +1307,7 @@ def check_files():
print("Creating empty {}".format(filename)) print("Creating empty {}".format(filename))
dataIO.save_json("data/mod/{}".format(filename), value) dataIO.save_json("data/mod/{}".format(filename), value)
def setup(bot): def setup(bot):
global logger global logger
check_folders() check_folders()