mirror of
https://github.com/brandons209/Red-bot-Cogs.git
synced 2024-05-05 21:13:46 +12:00
add black code formatter gitaction, update all cogs to follow format
This commit is contained in:
parent
7e4b0c18b8
commit
f5891ffb90
13
.github/workflows/black-checker.yml
vendored
Normal file
13
.github/workflows/black-checker.yml
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
name: black-checker
|
||||
|
||||
on: [pull_request, push]
|
||||
|
||||
jobs:
|
||||
black:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Black Code Formatter
|
||||
uses: lgeiger/black-action@v1.0.1
|
||||
with:
|
||||
args: "--line-length 120 --target-version py38 --check ."
|
|
@ -1,5 +1,6 @@
|
|||
from .activitylog import ActivityLogger
|
||||
|
||||
|
||||
async def setup(bot):
|
||||
n = ActivityLogger(bot)
|
||||
await n.initialize()
|
||||
|
|
|
@ -12,13 +12,9 @@ import os
|
|||
import asyncio
|
||||
import glob
|
||||
|
||||
__version__ = '3.0.0'
|
||||
__version__ = "3.0.0"
|
||||
|
||||
TIMESTAMP_FORMAT = '%Y-%m-%d %X' # YYYY-MM-DD HH:MM:SS
|
||||
#PATH_LIST = ['data', 'activitylogger']
|
||||
#JSON = os.path.join(*PATH_LIST, "settings.json")
|
||||
#NAMES_JSON = os.path.join(*PATH_LIST, "past_names.json")
|
||||
EDIT_TIMEDELTA = timedelta(seconds=3)
|
||||
TIMESTAMP_FORMAT = "%Y-%m-%d %X" # YYYY-MM-DD HH:MM:SS
|
||||
|
||||
# 0 is Message object
|
||||
AUTHOR_TEMPLATE = "@{0.author.name}#{0.author.discriminator}(id:{0.author.id})"
|
||||
|
@ -42,6 +38,7 @@ DELETE_AUDIT_TEMPLATE = "@{0.name}#{0.discriminator}(id:{0.id}) deleted message
|
|||
|
||||
MAX_LINES = 50000
|
||||
|
||||
|
||||
def get_all_names(guild_files, user):
|
||||
names = [str(user)]
|
||||
for log in guild_files:
|
||||
|
@ -68,19 +65,21 @@ def get_all_names(guild_files, user):
|
|||
names.append(username)
|
||||
return set(names)
|
||||
|
||||
def format_list(*items, join='and', delim=', '):
|
||||
|
||||
def format_list(*items, join="and", delim=", "):
|
||||
if len(items) > 1:
|
||||
return (' %s ' % join).join((delim.join(items[:-1]), items[-1]))
|
||||
return (" %s " % join).join((delim.join(items[:-1]), items[-1]))
|
||||
elif items:
|
||||
return items[0]
|
||||
else:
|
||||
return ''
|
||||
return ""
|
||||
|
||||
|
||||
class LogHandle:
|
||||
"""basic wrapper for logfile handles, used to keep track of stale handles"""
|
||||
def __init__(self, path, time=None, mode='a', buf=1):
|
||||
self.handle = open(path, mode, buf, errors='backslashreplace')
|
||||
|
||||
def __init__(self, path, time=None, mode="a", buf=1):
|
||||
self.handle = open(path, mode, buf, errors="backslashreplace")
|
||||
self.lock = asyncio.Lock()
|
||||
|
||||
if time:
|
||||
|
@ -111,34 +110,13 @@ class ActivityLogger(commands.Cog):
|
|||
self.bot = bot
|
||||
self.config = Config.get_conf(self, identifier=9584736583, force_registration=True)
|
||||
default_global = {
|
||||
"attrs": {
|
||||
"attachments" : False,
|
||||
"default" : False,
|
||||
"direct" : False,
|
||||
"everything" : False,
|
||||
"rotation" : "m"
|
||||
}
|
||||
}
|
||||
self.default_guild = {
|
||||
"all_s": False,
|
||||
"voice": False,
|
||||
"events": False,
|
||||
"prefixes": []
|
||||
}
|
||||
self.default_channel = {
|
||||
"enabled": False
|
||||
}
|
||||
default_user = {
|
||||
"past_names": []
|
||||
"attrs": {"attachments": False, "default": False, "direct": False, "everything": False, "rotation": "m"}
|
||||
}
|
||||
self.default_guild = {"all_s": False, "voice": False, "events": False, "prefixes": []}
|
||||
self.default_channel = {"enabled": False}
|
||||
default_user = {"past_names": []}
|
||||
default_member = {
|
||||
"stats": {
|
||||
"total_msg": 0,
|
||||
"bot_cmd": 0,
|
||||
"avg_len": 0.0,
|
||||
"vc_time_sec": 0.0,
|
||||
"last_vc_time": None
|
||||
}
|
||||
"stats": {"total_msg": 0, "bot_cmd": 0, "avg_len": 0.0, "vc_time_sec": 0.0, "last_vc_time": None}
|
||||
}
|
||||
self.config.register_global(**default_global)
|
||||
self.config.register_guild(**self.default_guild)
|
||||
|
@ -203,9 +181,7 @@ class ActivityLogger(commands.Cog):
|
|||
since_joined = "?"
|
||||
user_joined = "Unknown"
|
||||
user_created = user.created_at.strftime("%b %d, %Y %H:%M UTC")
|
||||
member_number = (sorted(guild.members,
|
||||
key=lambda m: m.joined_at or ctx.message.created_at)
|
||||
.index(user) + 1)
|
||||
member_number = sorted(guild.members, key=lambda m: m.joined_at or ctx.message.created_at).index(user) + 1
|
||||
|
||||
created_on = "{}\n({} days ago)".format(user_created, since_created)
|
||||
joined_on = "{}\n({} days ago)".format(user_joined, since_joined)
|
||||
|
@ -243,8 +219,7 @@ class ActivityLogger(commands.Cog):
|
|||
names = pagify(names, page_length=1000)
|
||||
for name in names:
|
||||
data.add_field(name="Also known as:", value=name, inline=False)
|
||||
data.set_footer(text="Member #{} | User ID:{}"
|
||||
"".format(member_number, user.id))
|
||||
data.set_footer(text="Member #{} | User ID:{}" "".format(member_number, user.id))
|
||||
|
||||
name = str(user)
|
||||
name = " ~ ".join((name, user.nick)) if user.nick else name
|
||||
|
@ -274,7 +249,7 @@ class ActivityLogger(commands.Cog):
|
|||
stats = await self.config.member(user).stats()
|
||||
async with self.config.user(user).past_names() as past_names:
|
||||
if not past_names:
|
||||
guild_files = sorted(glob.glob(os.path.join(PATH, 'usernames', "*.log")))
|
||||
guild_files = sorted(glob.glob(os.path.join(PATH, "usernames", "*.log")))
|
||||
names = get_all_names(guild_files, user)
|
||||
else:
|
||||
names = past_names
|
||||
|
@ -306,7 +281,9 @@ class ActivityLogger(commands.Cog):
|
|||
msg += "Average message length: `{:.2f}` words\n".format(avg_len / (num_messages - num_bot_commands))
|
||||
except ZeroDivisionError:
|
||||
msg += "Average message length: `{:.2f}` words\n".format(0)
|
||||
msg += "Time spent in voice chat: `{:.0f}` {}.\n".format(minutes if minutes <= 120 else hours, "minutes" if minutes <= 120 else "hours")
|
||||
msg += "Time spent in voice chat: `{:.0f}` {}.\n".format(
|
||||
minutes if minutes <= 120 else hours, "minutes" if minutes <= 120 else "hours"
|
||||
)
|
||||
msg += f"Bans: `{bans}`, Kicks: `{kicks}`, Mutes: `{mutes}`"
|
||||
if len(names) > 1:
|
||||
return msg, format_list(*names)
|
||||
|
@ -351,12 +328,12 @@ class ActivityLogger(commands.Cog):
|
|||
messages = [message for message in messages if str(user.id) in message]
|
||||
|
||||
message_chunks = [
|
||||
messages[i * MAX_LINES:(i + 1) * MAX_LINES] for i in range((len(messages) + MAX_LINES - 1) // MAX_LINES)
|
||||
messages[i * MAX_LINES : (i + 1) * MAX_LINES] for i in range((len(messages) + MAX_LINES - 1) // MAX_LINES)
|
||||
]
|
||||
|
||||
for msgs in message_chunks:
|
||||
temp_file = os.path.join(log_path, datetime.utcnow().strftime("%Y%m%d%X").replace(":", "") + ".txt")
|
||||
with open(temp_file, encoding='utf-8', mode="w") as f:
|
||||
with open(temp_file, encoding="utf-8", mode="w") as f:
|
||||
f.writelines(msgs)
|
||||
|
||||
await ctx.channel.send(file=discord.File(temp_file))
|
||||
|
@ -436,12 +413,12 @@ class ActivityLogger(commands.Cog):
|
|||
"""
|
||||
try:
|
||||
dates = date.split(";")
|
||||
dates = [dates[0].strip(), dates[1].strip()] # only use 2 dates
|
||||
dates = [dates[0].strip(), dates[1].strip()] # only use 2 dates
|
||||
start, end = [parse_time(date).replace(tzinfo=None) for date in dates]
|
||||
# order doesnt matter, so check which date is older than the other
|
||||
# end time should be the newest date since logs are processed in reverse
|
||||
if start < end: # start is before end date
|
||||
start, end = end, start # swap order
|
||||
if start < end: # start is before end date
|
||||
start, end = end, start # swap order
|
||||
except:
|
||||
await ctx.send("Invalid dates! Try again.")
|
||||
return
|
||||
|
@ -530,12 +507,12 @@ class ActivityLogger(commands.Cog):
|
|||
"""
|
||||
try:
|
||||
dates = date.split(";")
|
||||
dates = [dates[0].strip(), dates[1].strip()] # only use 2 dates
|
||||
dates = [dates[0].strip(), dates[1].strip()] # only use 2 dates
|
||||
start, end = [parse_time(date).replace(tzinfo=None) for date in dates]
|
||||
# order doesnt matter, so check which date is older than the other
|
||||
# end time should be the newest date since logs are processed in reverse
|
||||
if start < end: # start is before end date
|
||||
start, end = end, start # swap order
|
||||
if start < end: # start is before end date
|
||||
start, end = end, start # swap order
|
||||
except:
|
||||
await ctx.send("Invalid dates! Try again.")
|
||||
return
|
||||
|
@ -624,12 +601,12 @@ class ActivityLogger(commands.Cog):
|
|||
"""
|
||||
try:
|
||||
dates = date.split(";")
|
||||
dates = [dates[0].strip(), dates[1].strip()] # only use 2 dates
|
||||
dates = [dates[0].strip(), dates[1].strip()] # only use 2 dates
|
||||
start, end = [parse_time(date).replace(tzinfo=None) for date in dates]
|
||||
# order doesnt matter, so check which date is older than the other
|
||||
# end time should be the newest date since logs are processed in reverse
|
||||
if start < end: # start is before end date
|
||||
start, end = end, start # swap order
|
||||
if start < end: # start is before end date
|
||||
start, end = end, start # swap order
|
||||
except:
|
||||
await ctx.send("Invalid dates! Try again.")
|
||||
return
|
||||
|
@ -719,12 +696,12 @@ class ActivityLogger(commands.Cog):
|
|||
"""
|
||||
try:
|
||||
dates = date.split(";")
|
||||
dates = [dates[0].strip(), dates[1].strip()] # only use 2 dates
|
||||
dates = [dates[0].strip(), dates[1].strip()] # only use 2 dates
|
||||
start, end = [parse_time(date).replace(tzinfo=None) for date in dates]
|
||||
# order doesnt matter, so check which date is older than the other
|
||||
# end time should be the newest date since logs are processed in reverse
|
||||
if start < end: # start is before end date
|
||||
start, end = end, start # swap order
|
||||
if start < end: # start is before end date
|
||||
start, end = end, start # swap order
|
||||
except:
|
||||
await ctx.send("Invalid dates! Try again.")
|
||||
return
|
||||
|
@ -746,7 +723,7 @@ class ActivityLogger(commands.Cog):
|
|||
"""
|
||||
pass
|
||||
|
||||
@logset.command(name='everything', aliases=['global'])
|
||||
@logset.command(name="everything", aliases=["global"])
|
||||
async def set_everything(self, ctx, on_off: bool = None):
|
||||
"""
|
||||
Global override for all logging
|
||||
|
@ -762,7 +739,7 @@ class ActivityLogger(commands.Cog):
|
|||
else:
|
||||
await ctx.send("Global logging override is disabled.")
|
||||
|
||||
@logset.command(name='default')
|
||||
@logset.command(name="default")
|
||||
async def set_default(self, ctx, on_off: bool = None):
|
||||
"""
|
||||
Sets whether logging is on or off where unset
|
||||
|
@ -780,7 +757,7 @@ class ActivityLogger(commands.Cog):
|
|||
else:
|
||||
await ctx.send("Logging is disabled by default.")
|
||||
|
||||
@logset.command(name='dm')
|
||||
@logset.command(name="dm")
|
||||
async def set_direct(self, ctx, on_off: bool = None):
|
||||
"""
|
||||
Log direct messages?
|
||||
|
@ -797,7 +774,7 @@ class ActivityLogger(commands.Cog):
|
|||
else:
|
||||
await ctx.send("Logging of direct messages is disabled.")
|
||||
|
||||
@logset.command(name='attachments')
|
||||
@logset.command(name="attachments")
|
||||
async def set_attachments(self, ctx, on_off: bool = None):
|
||||
"""
|
||||
Download message attachments?
|
||||
|
@ -813,7 +790,7 @@ class ActivityLogger(commands.Cog):
|
|||
else:
|
||||
await ctx.send("Downloading of attachments is disabled.")
|
||||
|
||||
@logset.command(name='channel')
|
||||
@logset.command(name="channel")
|
||||
@commands.guild_only()
|
||||
async def set_channel(self, ctx, on_off: bool, channel: discord.TextChannel = None):
|
||||
"""
|
||||
|
@ -830,11 +807,11 @@ class ActivityLogger(commands.Cog):
|
|||
await self.config.channel(channel).enabled.set(on_off)
|
||||
|
||||
if on_off:
|
||||
await ctx.send('Logging enabled for %s' % channel.mention)
|
||||
await ctx.send("Logging enabled for %s" % channel.mention)
|
||||
else:
|
||||
await ctx.send('Logging disabled for %s' % channel.mention)
|
||||
await ctx.send("Logging disabled for %s" % channel.mention)
|
||||
|
||||
@logset.command(name='server')
|
||||
@logset.command(name="server")
|
||||
@commands.guild_only()
|
||||
async def set_guild(self, ctx, on_off: bool):
|
||||
"""
|
||||
|
@ -846,11 +823,11 @@ class ActivityLogger(commands.Cog):
|
|||
await self.config.guild(guild).all_s.set(on_off)
|
||||
|
||||
if on_off:
|
||||
await ctx.send('Logging enabled for %s' % guild)
|
||||
await ctx.send("Logging enabled for %s" % guild)
|
||||
else:
|
||||
await ctx.send('Logging disabled for %s' % guild)
|
||||
await ctx.send("Logging disabled for %s" % guild)
|
||||
|
||||
@logset.command(name='voice')
|
||||
@logset.command(name="voice")
|
||||
@commands.guild_only()
|
||||
async def set_voice(self, ctx, on_off: bool):
|
||||
"""
|
||||
|
@ -862,11 +839,11 @@ class ActivityLogger(commands.Cog):
|
|||
await self.config.guild(guild).voice.set(on_off)
|
||||
|
||||
if on_off:
|
||||
await ctx.send('Voice event logging enabled for %s' % guild)
|
||||
await ctx.send("Voice event logging enabled for %s" % guild)
|
||||
else:
|
||||
await ctx.send('Voice event logging disabled for %s' % guild)
|
||||
await ctx.send("Voice event logging disabled for %s" % guild)
|
||||
|
||||
@logset.command(name='events')
|
||||
@logset.command(name="events")
|
||||
@commands.guild_only()
|
||||
async def set_events(self, ctx, on_off: bool):
|
||||
"""
|
||||
|
@ -878,9 +855,9 @@ class ActivityLogger(commands.Cog):
|
|||
await self.config.guild(guild).events.set(on_off)
|
||||
|
||||
if on_off:
|
||||
await ctx.send('Logging enabled for guild events in %s' % guild)
|
||||
await ctx.send("Logging enabled for guild events in %s" % guild)
|
||||
else:
|
||||
await ctx.send('Logging disabled for guild events in %s' % guild)
|
||||
await ctx.send("Logging disabled for guild events in %s" % guild)
|
||||
|
||||
@logset.command(name="prefixes")
|
||||
@commands.guild_only()
|
||||
|
@ -895,16 +872,16 @@ class ActivityLogger(commands.Cog):
|
|||
await self.config.guild(ctx.guild).prefixes.set([ctx.clean_prefix])
|
||||
self.cache[ctx.guild.id]["prefixes"] = [ctx.clean_prefix]
|
||||
return
|
||||
await ctx.send("Current Prefixes: " + format_list(*curr, delim=', '))
|
||||
await ctx.send("Current Prefixes: " + format_list(*curr, delim=", "))
|
||||
return
|
||||
|
||||
prefixes = [p for p in prefixes if p != ' ']
|
||||
prefixes = [p for p in prefixes if p != " "]
|
||||
await self.config.guild(ctx.guild).prefixes.set(prefixes)
|
||||
self.cache[ctx.guild.id]["prefixes"] = prefixes
|
||||
prefixes = [f"`{p}`" for p in prefixes]
|
||||
await ctx.send("Prefixes set to: " + format_list(*prefixes, delim=', '))
|
||||
await ctx.send("Prefixes set to: " + format_list(*prefixes, delim=", "))
|
||||
|
||||
@logset.command(name='rotation')
|
||||
@logset.command(name="rotation")
|
||||
async def set_rotation(self, ctx, freq: str = None):
|
||||
"""
|
||||
Show, disable, or set the log rotation period
|
||||
|
@ -921,12 +898,12 @@ class ActivityLogger(commands.Cog):
|
|||
- y: one log file per year (starts 00:00Z Jan 1)
|
||||
"""
|
||||
if freq:
|
||||
freq = freq.lower().strip('"\'` ')
|
||||
freq = freq.lower().strip("\"'` ")
|
||||
|
||||
if freq in ('d', 'w', 'm', 'y', 'none', 'disable'):
|
||||
adj = 'now'
|
||||
if freq in ("d", "w", "m", "y", "none", "disable"):
|
||||
adj = "now"
|
||||
|
||||
if freq in ('none', 'disable'):
|
||||
if freq in ("none", "disable"):
|
||||
freq = None
|
||||
|
||||
async with self.config.attrs() as attrs:
|
||||
|
@ -937,53 +914,48 @@ class ActivityLogger(commands.Cog):
|
|||
await self.bot.send_cmd_help(ctx)
|
||||
return
|
||||
else:
|
||||
adj = 'currently'
|
||||
adj = "currently"
|
||||
freq = self.cache["rotation"]
|
||||
|
||||
if not freq:
|
||||
await ctx.send("Log rotation is %s disabled." % adj)
|
||||
else:
|
||||
desc = {
|
||||
'd' : 'daily',
|
||||
'w' : 'weekly',
|
||||
'm' : 'monthly',
|
||||
'y' : 'yearly'
|
||||
}[freq]
|
||||
desc = {"d": "daily", "w": "weekly", "m": "monthly", "y": "yearly"}[freq]
|
||||
|
||||
await ctx.send('Log rotation period is %s %s.' % (adj, desc))
|
||||
await ctx.send("Log rotation period is %s %s." % (adj, desc))
|
||||
|
||||
@staticmethod
|
||||
def format_rotation_string(timestamp, rotation_code, filename=None):
|
||||
kwargs = dict(hour=0, minute=0, second=0, microsecond=0)
|
||||
|
||||
if not rotation_code:
|
||||
return filename or ''
|
||||
return filename or ""
|
||||
|
||||
if rotation_code == 'y':
|
||||
if rotation_code == "y":
|
||||
kwargs.update(day=1, month=1)
|
||||
start = timestamp.replace(**kwargs)
|
||||
elif rotation_code == 'm':
|
||||
elif rotation_code == "m":
|
||||
kwargs.update(day=1)
|
||||
start = timestamp.replace(**kwargs)
|
||||
elif rotation_code == 'w':
|
||||
elif rotation_code == "w":
|
||||
start = timestamp - timedelta(days=timestamp.weekday())
|
||||
|
||||
spec = start.strftime('%Y%m%d')
|
||||
spec = start.strftime("%Y%m%d")
|
||||
|
||||
if rotation_code == 'w':
|
||||
spec += '--P7D'
|
||||
if rotation_code == "w":
|
||||
spec += "--P7D"
|
||||
else:
|
||||
spec += '--P1%c' % rotation_code.upper()
|
||||
spec += "--P1%c" % rotation_code.upper()
|
||||
|
||||
if filename:
|
||||
return '%s_%s' % (spec, filename)
|
||||
return "%s_%s" % (spec, filename)
|
||||
else:
|
||||
return spec
|
||||
|
||||
@staticmethod
|
||||
def get_voice_flags(voice_state):
|
||||
flags = []
|
||||
for f in ('deaf', 'mute', 'self_deaf', 'self_mute', 'self_stream', 'self_video'):
|
||||
for f in ("deaf", "mute", "self_deaf", "self_mute", "self_stream", "self_video"):
|
||||
if getattr(voice_state, f, None):
|
||||
flags.append(f)
|
||||
|
||||
|
@ -992,11 +964,13 @@ class ActivityLogger(commands.Cog):
|
|||
@staticmethod
|
||||
def format_overwrite(target, channel, before, after, user=None):
|
||||
if user:
|
||||
target_str = 'Channel overwrites by @{1.name}#{1.discriminator}(id:{1.id}): {0.name} ({0.id}): '.format(channel, user)
|
||||
target_str = "Channel overwrites by @{1.name}#{1.discriminator}(id:{1.id}): {0.name} ({0.id}): ".format(
|
||||
channel, user
|
||||
)
|
||||
else:
|
||||
target_str = 'Channel overwrites: {0.name} ({0.id}): '.format(channel)
|
||||
target_str += 'role' if isinstance(target, discord.Role) else 'member'
|
||||
target_str += ' {0.name} ({0.id})'.format(target)
|
||||
target_str = "Channel overwrites: {0.name} ({0.id}): ".format(channel)
|
||||
target_str += "role" if isinstance(target, discord.Role) else "member"
|
||||
target_str += " {0.name} ({0.id})".format(target)
|
||||
|
||||
if before:
|
||||
bpair = [x.value for x in before.pair()]
|
||||
|
@ -1005,14 +979,14 @@ class ActivityLogger(commands.Cog):
|
|||
apair = [x.value for x in after.pair()]
|
||||
|
||||
if before and after:
|
||||
fmt = ' updated to values %i, %i (was %i, %i)'
|
||||
fmt = " updated to values %i, %i (was %i, %i)"
|
||||
return target_str + fmt % tuple(apair + bpair)
|
||||
elif after:
|
||||
return target_str + ' added with values %i, %i' % tuple(apair)
|
||||
return target_str + " added with values %i, %i" % tuple(apair)
|
||||
elif before:
|
||||
return target_str + ' removed (was %i, %i)' % tuple(bpair)
|
||||
return target_str + " removed (was %i, %i)" % tuple(bpair)
|
||||
|
||||
def gethandle(self, path, mode='a'):
|
||||
def gethandle(self, path, mode="a"):
|
||||
"""Manages logfile handles, culling stale ones and creating folders"""
|
||||
if path in self.handles:
|
||||
if os.path.exists(path):
|
||||
|
@ -1047,34 +1021,34 @@ class ActivityLogger(commands.Cog):
|
|||
return handle
|
||||
|
||||
def should_log(self, location):
|
||||
if self.cache.get('everything', False):
|
||||
if self.cache.get("everything", False):
|
||||
return True
|
||||
|
||||
default = self.cache.get('default', False)
|
||||
default = self.cache.get("default", False)
|
||||
|
||||
if type(location) is discord.Guild:
|
||||
loc = self.cache[location.id]
|
||||
return loc.get('all_s', False) or loc.get('events', default)
|
||||
return loc.get("all_s", False) or loc.get("events", default)
|
||||
|
||||
elif type(location) is discord.TextChannel:
|
||||
loc = self.cache[location.guild.id]
|
||||
opts = [loc.get('all_s', False), self.cache[location.id].get("enabled", default)]
|
||||
opts = [loc.get("all_s", False), self.cache[location.id].get("enabled", default)]
|
||||
return any(opts)
|
||||
|
||||
elif type(location) is discord.VoiceChannel:
|
||||
loc = self.cache[location.guild.id]
|
||||
opts = [loc.get('all_s', False), loc.get('voice', False)]
|
||||
opts = [loc.get("all_s", False), loc.get("voice", False)]
|
||||
|
||||
return any(opts)
|
||||
|
||||
elif isinstance(location, discord.abc.PrivateChannel):
|
||||
return self.cache.get('direct', default)
|
||||
return self.cache.get("direct", default)
|
||||
|
||||
else: # can't log other types
|
||||
return False
|
||||
|
||||
def should_download(self, msg):
|
||||
return self.should_log(msg.channel) and self.cache.get('attachments', False)
|
||||
return self.should_log(msg.channel) and self.cache.get("attachments", False)
|
||||
|
||||
def process_attachment(self, message, a):
|
||||
aid = a.id
|
||||
|
@ -1086,23 +1060,23 @@ class ActivityLogger(commands.Cog):
|
|||
if type(channel) is discord.TextChannel:
|
||||
guildid = channel.guild.id
|
||||
elif isinstance(channel, discord.abc.PrivateChannel):
|
||||
guildid = 'direct'
|
||||
guildid = "direct"
|
||||
|
||||
path = os.path.join(path, str(guildid), str(channel.id) + '_attachments')
|
||||
filename = str(aid) + '_' + aname
|
||||
path = os.path.join(path, str(guildid), str(channel.id) + "_attachments")
|
||||
filename = str(aid) + "_" + aname
|
||||
|
||||
if len(filename) > 255:
|
||||
target_len = 255 - len(aid) - 4
|
||||
part_a = target_len // 2
|
||||
part_b = target_len - part_a
|
||||
filename = aid + '_' + aname[:part_a] + '...' + aname[-part_b:]
|
||||
filename = aid + "_" + aname[:part_a] + "..." + aname[-part_b:]
|
||||
truncated = True
|
||||
else:
|
||||
truncated = False
|
||||
|
||||
return aid, url, path, filename, truncated
|
||||
|
||||
async def log(self, location, text, timestamp=None, force=False, subfolder=None, mode='a'):
|
||||
async def log(self, location, text, timestamp=None, force=False, subfolder=None, mode="a"):
|
||||
if not timestamp:
|
||||
timestamp = datetime.utcnow()
|
||||
|
||||
|
@ -1111,24 +1085,24 @@ class ActivityLogger(commands.Cog):
|
|||
|
||||
path = []
|
||||
entry = [timestamp.strftime(TIMESTAMP_FORMAT)]
|
||||
rotation = self.cache['rotation']
|
||||
rotation = self.cache["rotation"]
|
||||
if type(location) is discord.Guild:
|
||||
path += [str(location.id), 'guild.log']
|
||||
path += [str(location.id), "guild.log"]
|
||||
elif type(location) is discord.TextChannel or type(location) is discord.VoiceChannel:
|
||||
guildid = str(location.guild.id)
|
||||
entry.append('#' + location.name)
|
||||
path += [guildid, str(location.id) + '.log']
|
||||
entry.append("#" + location.name)
|
||||
path += [guildid, str(location.id) + ".log"]
|
||||
elif isinstance(location, discord.abc.PrivateChannel):
|
||||
path += ['direct', str(location.id) + '.log']
|
||||
path += ["direct", str(location.id) + ".log"]
|
||||
elif type(location) is discord.User or type(location) is discord.Member:
|
||||
path += ['usernames', 'usernames.log']
|
||||
path += ["usernames", "usernames.log"]
|
||||
else:
|
||||
return
|
||||
|
||||
if subfolder:
|
||||
path.insert(-1, str(subfolder))
|
||||
|
||||
text = text.replace('\n', '\\n')
|
||||
text = text.replace("\n", "\\n")
|
||||
entry.append(text)
|
||||
|
||||
if rotation:
|
||||
|
@ -1136,7 +1110,7 @@ class ActivityLogger(commands.Cog):
|
|||
|
||||
fname = os.path.join(PATH, *path)
|
||||
handle = self.gethandle(fname, mode=mode)
|
||||
await handle.write(' '.join(entry) + '\n')
|
||||
await handle.write(" ".join(entry) + "\n")
|
||||
|
||||
async def message_handler(self, message, *args, force_attachments=None, **kwargs):
|
||||
dl_attachment = self.should_download(message)
|
||||
|
@ -1149,15 +1123,17 @@ class ActivityLogger(commands.Cog):
|
|||
for a in message.attachments:
|
||||
attachments += [self.process_attachment(message, a)]
|
||||
|
||||
entry = DOWNLOAD_TEMPLATE.format(message, [a[3] + ' (filename truncated)' if a[4] else a[3] for a in attachments])
|
||||
entry = DOWNLOAD_TEMPLATE.format(
|
||||
message, [a[3] + " (filename truncated)" if a[4] else a[3] for a in attachments]
|
||||
)
|
||||
|
||||
elif message.attachments:
|
||||
urls = ','.join(a.url for a in message.attachments)
|
||||
urls = ",".join(a.url for a in message.attachments)
|
||||
entry = ATTACHMENT_TEMPLATE.format(message, urls)
|
||||
else:
|
||||
entry = MESSAGE_TEMPLATE.format(message)
|
||||
|
||||
if message.author.id != self.bot.user.id: # don't calculate bot stats
|
||||
if message.author.id != self.bot.user.id: # don't calculate bot stats
|
||||
async with self.config.member(message.author).stats() as stats:
|
||||
stats["total_msg"] += 1
|
||||
if len(message.content) > 0 and message.content[0] in self.cache[message.guild.id]["prefixes"]:
|
||||
|
@ -1199,10 +1175,12 @@ class ActivityLogger(commands.Cog):
|
|||
async for entry in message.guild.audit_logs(limit=1):
|
||||
# target is user who had message deleted
|
||||
if entry.action is discord.AuditLogAction.message_delete:
|
||||
if entry.target.id == message.author.id and \
|
||||
entry.extra.channel.id == message.channel.id and \
|
||||
entry.created_at.timestamp() > time.time() - 3000 and \
|
||||
entry.extra.count >= 1:
|
||||
if (
|
||||
entry.target.id == message.author.id
|
||||
and entry.extra.channel.id == message.channel.id
|
||||
and entry.created_at.timestamp() > time.time() - 3000
|
||||
and entry.extra.count >= 1
|
||||
):
|
||||
entry_s = DELETE_AUDIT_TEMPLATE.format(entry.user, message, message.author, timestamp)
|
||||
break
|
||||
except:
|
||||
|
@ -1215,12 +1193,12 @@ class ActivityLogger(commands.Cog):
|
|||
|
||||
@commands.Cog.listener()
|
||||
async def on_guild_join(self, guild):
|
||||
entry = 'this bot joined the guild'
|
||||
entry = "this bot joined the guild"
|
||||
await self.log(guild, entry)
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_guild_remove(self, guild):
|
||||
entry = 'this bot left the guild'
|
||||
entry = "this bot left the guild"
|
||||
await self.log(guild, entry)
|
||||
|
||||
@commands.Cog.listener()
|
||||
|
@ -1230,39 +1208,49 @@ class ActivityLogger(commands.Cog):
|
|||
try:
|
||||
async for entry in after.audit_logs(limit=1):
|
||||
if entry.action is discord.AuditLogAction.guild_update:
|
||||
user = entry.user
|
||||
user = entry.user
|
||||
except:
|
||||
pass
|
||||
|
||||
if before.owner != after.owner:
|
||||
if user:
|
||||
entries.append('guild owner changed by @{2.name}#{2.discriminator}(id:{2.id}), from {0.owner} (id {0.owner.id}) to {1.owner} (id {1.owner.id})')
|
||||
entries.append(
|
||||
"guild owner changed by @{2.name}#{2.discriminator}(id:{2.id}), from {0.owner} (id {0.owner.id}) to {1.owner} (id {1.owner.id})"
|
||||
)
|
||||
else:
|
||||
entries.append('guild owner changed from {0.owner} (id {0.owner.id}) to {1.owner} (id {1.owner.id})')
|
||||
entries.append("guild owner changed from {0.owner} (id {0.owner.id}) to {1.owner} (id {1.owner.id})")
|
||||
|
||||
if before.region != after.region:
|
||||
if user:
|
||||
entries.append('guild region changed by @{2.name}#{2.discriminator}(id:{2.id}), from {0.region} to {1.region}')
|
||||
entries.append(
|
||||
"guild region changed by @{2.name}#{2.discriminator}(id:{2.id}), from {0.region} to {1.region}"
|
||||
)
|
||||
else:
|
||||
entries.append('guild region changed from {0.region} to {1.region}')
|
||||
entries.append("guild region changed from {0.region} to {1.region}")
|
||||
|
||||
if before.name != after.name:
|
||||
if user:
|
||||
entries.append('guild name changed by @{2.name}#{2.discriminator}(id:{2.id}), from "{0.name}" to "{1.name}"')
|
||||
entries.append(
|
||||
'guild name changed by @{2.name}#{2.discriminator}(id:{2.id}), from "{0.name}" to "{1.name}"'
|
||||
)
|
||||
else:
|
||||
entries.append('guild name changed from "{0.name}" to "{1.name}"')
|
||||
|
||||
if before.icon_url != after.icon_url:
|
||||
if user:
|
||||
entries.append('guild icon changed by @{2.name}#{2.discriminator}(id:{2.id}), from {0.icon_url} to {1.icon_url}')
|
||||
entries.append(
|
||||
"guild icon changed by @{2.name}#{2.discriminator}(id:{2.id}), from {0.icon_url} to {1.icon_url}"
|
||||
)
|
||||
else:
|
||||
entries.append('guild icon changed from {0.icon_url} to {1.icon_url}')
|
||||
entries.append("guild icon changed from {0.icon_url} to {1.icon_url}")
|
||||
|
||||
if before.splash != after.splash:
|
||||
if user:
|
||||
entries.append('guild splash changed by @{2.name}#{2.discriminator}(id:{2.id}), from {0.splash} to {1.splash}')
|
||||
entries.append(
|
||||
"guild splash changed by @{2.name}#{2.discriminator}(id:{2.id}), from {0.splash} to {1.splash}"
|
||||
)
|
||||
else:
|
||||
entries.append('guild splash changed from {0.splash} to {1.splash}')
|
||||
entries.append("guild splash changed from {0.splash} to {1.splash}")
|
||||
|
||||
for e in entries:
|
||||
if user:
|
||||
|
@ -1326,45 +1314,61 @@ class ActivityLogger(commands.Cog):
|
|||
|
||||
if before.color != after.color:
|
||||
if user:
|
||||
entries.append('Role color by @{2.name}#{2.discriminator}(id:{2.id}): "{0}" (id {0.id}) changed from {0.color} to {1.color}')
|
||||
entries.append(
|
||||
'Role color by @{2.name}#{2.discriminator}(id:{2.id}): "{0}" (id {0.id}) changed from {0.color} to {1.color}'
|
||||
)
|
||||
else:
|
||||
entries.append('Role color: "{0}" (id {0.id}) changed from {0.color} to {1.color}')
|
||||
|
||||
if before.mentionable != after.mentionable:
|
||||
if after.mentionable:
|
||||
if user:
|
||||
entries.append('Role mentionable by @{2.name}#{2.discriminator}(id:{2.id}): "{1.name}" (id {1.id}) is now mentionable')
|
||||
entries.append(
|
||||
'Role mentionable by @{2.name}#{2.discriminator}(id:{2.id}): "{1.name}" (id {1.id}) is now mentionable'
|
||||
)
|
||||
else:
|
||||
entries.append('Role mentionable: "{1.name}" (id {1.id}) is now mentionable')
|
||||
else:
|
||||
if user:
|
||||
entries.append('Role mentionable by @{2.name}#{2.discriminator}(id:{2.id}): "{1.name}" (id {1.id}) is no longer mentionable')
|
||||
entries.append(
|
||||
'Role mentionable by @{2.name}#{2.discriminator}(id:{2.id}): "{1.name}" (id {1.id}) is no longer mentionable'
|
||||
)
|
||||
else:
|
||||
entries.append('Role mentionable: "{1.name}" (id {1.id}) is no longer mentionable')
|
||||
|
||||
if before.hoist != after.hoist:
|
||||
if after.hoist:
|
||||
if user:
|
||||
entries.append('Role hoist by @{2.name}#{2.discriminator}(id:{2.id}): "{1.name}" (id {1.id}) is now shown seperately')
|
||||
entries.append(
|
||||
'Role hoist by @{2.name}#{2.discriminator}(id:{2.id}): "{1.name}" (id {1.id}) is now shown seperately'
|
||||
)
|
||||
else:
|
||||
entries.append('Role hoist: "{1.name}" (id {1.id}) is now shown seperately')
|
||||
else:
|
||||
if user:
|
||||
entries.append('Role hoist by @{2.name}#{2.discriminator}(id:{2.id}): "{1.name}" (id {1.id}) is no longer shown seperately')
|
||||
entries.append(
|
||||
'Role hoist by @{2.name}#{2.discriminator}(id:{2.id}): "{1.name}" (id {1.id}) is no longer shown seperately'
|
||||
)
|
||||
else:
|
||||
entries.append('Role hoist: "{1.name}" (id {1.id}) is no longer shown seperately')
|
||||
|
||||
if before.permissions != after.permissions:
|
||||
if user:
|
||||
entries.append('Role permissions by @{2.name}#{2.discriminator}(id:{2.id}): "{1.name}" (id {1.id}) changed from {0.permissions.value} '
|
||||
'to {1.permissions.value}')
|
||||
entries.append(
|
||||
'Role permissions by @{2.name}#{2.discriminator}(id:{2.id}): "{1.name}" (id {1.id}) changed from {0.permissions.value} '
|
||||
"to {1.permissions.value}"
|
||||
)
|
||||
else:
|
||||
entries.append('Role permissions: "{1.name}" (id {1.id}) changed from {0.permissions.value} '
|
||||
'to {1.permissions.value}')
|
||||
entries.append(
|
||||
'Role permissions: "{1.name}" (id {1.id}) changed from {0.permissions.value} '
|
||||
"to {1.permissions.value}"
|
||||
)
|
||||
|
||||
if before.position != after.position:
|
||||
if user:
|
||||
entries.append('Role position by @{2.name}#{2.discriminator}(id:{2.id}): "{0}" changed from {0.position} to {1.position}')
|
||||
entries.append(
|
||||
'Role position by @{2.name}#{2.discriminator}(id:{2.id}): "{0}" changed from {0.position} to {1.position}'
|
||||
)
|
||||
else:
|
||||
entries.append('Role position: "{0}" changed from {0.position} to {1.position}')
|
||||
|
||||
|
@ -1376,7 +1380,7 @@ class ActivityLogger(commands.Cog):
|
|||
|
||||
@commands.Cog.listener()
|
||||
async def on_member_join(self, member):
|
||||
entry = 'Member join: @{0} (id {0.id})'.format(member)
|
||||
entry = "Member join: @{0} (id {0.id})".format(member)
|
||||
|
||||
async with self.config.user(member).past_names() as past_names:
|
||||
if str(member) not in past_names:
|
||||
|
@ -1396,9 +1400,9 @@ class ActivityLogger(commands.Cog):
|
|||
pass
|
||||
|
||||
if user:
|
||||
entry = 'Member kicked by @{1.name}#{1.discriminator}(id:{1.id}): @{0} (id {0.id})'.format(member, user)
|
||||
entry = "Member kicked by @{1.name}#{1.discriminator}(id:{1.id}): @{0} (id {0.id})".format(member, user)
|
||||
else:
|
||||
entry = 'Member leave: @{0} (id {0.id})'.format(member)
|
||||
entry = "Member leave: @{0} (id {0.id})".format(member)
|
||||
|
||||
await self.config.member(member).clear()
|
||||
await self.log(member.guild, entry)
|
||||
|
@ -1415,9 +1419,9 @@ class ActivityLogger(commands.Cog):
|
|||
pass
|
||||
|
||||
if user:
|
||||
entry = 'Member banned by @{1.name}#{1.discriminator}(id:{1.id}): @{0} (id {0.id})'.format(member, user)
|
||||
entry = "Member banned by @{1.name}#{1.discriminator}(id:{1.id}): @{0} (id {0.id})".format(member, user)
|
||||
else:
|
||||
entry = 'Member ban: @{0} (id {0.id})'.format(member)
|
||||
entry = "Member ban: @{0} (id {0.id})".format(member)
|
||||
|
||||
await self.log(member.guild, entry)
|
||||
|
||||
|
@ -1433,9 +1437,9 @@ class ActivityLogger(commands.Cog):
|
|||
pass
|
||||
|
||||
if user:
|
||||
entry = 'Member unbanned by @{1.name}#{1.discriminator}(id:{1.id}): @{0} (id {0.id})'.format(member, user)
|
||||
entry = "Member unbanned by @{1.name}#{1.discriminator}(id:{1.id}): @{0} (id {0.id})".format(member, user)
|
||||
else:
|
||||
entry = 'Member unban: @{0} (id {0.id})'.format(member)
|
||||
entry = "Member unban: @{0} (id {0.id})".format(member)
|
||||
|
||||
await self.log(guild, entry)
|
||||
|
||||
|
@ -1445,8 +1449,10 @@ class ActivityLogger(commands.Cog):
|
|||
user = None
|
||||
try:
|
||||
async for entry in after.guild.audit_logs(limit=1):
|
||||
if entry.action is discord.AuditLogAction.member_update \
|
||||
or entry.action is discord.AuditLogAction.member_role_update:
|
||||
if (
|
||||
entry.action is discord.AuditLogAction.member_update
|
||||
or entry.action is discord.AuditLogAction.member_role_update
|
||||
):
|
||||
if entry.target.id == after.id:
|
||||
user = entry.user
|
||||
except:
|
||||
|
@ -1454,7 +1460,9 @@ class ActivityLogger(commands.Cog):
|
|||
|
||||
if before.nick != after.nick:
|
||||
if user:
|
||||
entries.append('Member nickname changed by @{2.name}#{2.discriminator}(id:{2.id}): "@{0}" (id {0.id}) nickname change from "{0.nick}" to "{1.nick}"')
|
||||
entries.append(
|
||||
'Member nickname changed by @{2.name}#{2.discriminator}(id:{2.id}): "@{0}" (id {0.id}) nickname change from "{0.nick}" to "{1.nick}"'
|
||||
)
|
||||
else:
|
||||
entries.append('Member nickname: "@{0}" (id {0.id}) changed nickname from "{0.nick}" to "{1.nick}"')
|
||||
|
||||
|
@ -1466,18 +1474,27 @@ class ActivityLogger(commands.Cog):
|
|||
|
||||
for r in added:
|
||||
if user:
|
||||
entries.append('Member role added by @{1.name}#{1.discriminator}(id:{1.id}): "{0}" (id {0.id}) role '
|
||||
'was added to "@{{0}}" (id {{0.id}})'.format(r, user))
|
||||
entries.append(
|
||||
'Member role added by @{1.name}#{1.discriminator}(id:{1.id}): "{0}" (id {0.id}) role '
|
||||
'was added to "@{{0}}" (id {{0.id}})'.format(r, user)
|
||||
)
|
||||
else:
|
||||
entries.append('Member role add: "{0}" (id {0.id}) role '
|
||||
'was added to "@{{0}}" (id {{0.id}})'.format(r))
|
||||
entries.append(
|
||||
'Member role add: "{0}" (id {0.id}) role ' 'was added to "@{{0}}" (id {{0.id}})'.format(r)
|
||||
)
|
||||
|
||||
for r in removed:
|
||||
if user:
|
||||
entries.append('Member role removed by @{1.name}#{1.discriminator}(id:{1.id}): "{0}" (id {0.id}) role was removed from "@{{0}}" (id {{0.id}})'.format(r, user))
|
||||
entries.append(
|
||||
'Member role removed by @{1.name}#{1.discriminator}(id:{1.id}): "{0}" (id {0.id}) role was removed from "@{{0}}" (id {{0.id}})'.format(
|
||||
r, user
|
||||
)
|
||||
)
|
||||
else:
|
||||
entries.append('Member role remove: "{0}" (id {0.id}) role '
|
||||
'was removed from "@{{0}}" (id {{0.id}})'.format(r))
|
||||
entries.append(
|
||||
'Member role remove: "{0}" (id {0.id}) role '
|
||||
'was removed from "@{{0}}" (id {{0.id}})'.format(r)
|
||||
)
|
||||
|
||||
for e in entries:
|
||||
await self.log(before.guild, e.format(before, after, user))
|
||||
|
@ -1513,7 +1530,9 @@ class ActivityLogger(commands.Cog):
|
|||
pass
|
||||
|
||||
if user:
|
||||
entry = 'Channel created by @{1.name}#{1.discriminator}(id:{1.id}): "{0.name}" (id {0.id})'.format(channel, user)
|
||||
entry = 'Channel created by @{1.name}#{1.discriminator}(id:{1.id}): "{0.name}" (id {0.id})'.format(
|
||||
channel, user
|
||||
)
|
||||
else:
|
||||
entry = 'Channel created: "{0.name}" (id {0.id})'.format(channel)
|
||||
|
||||
|
@ -1531,7 +1550,9 @@ class ActivityLogger(commands.Cog):
|
|||
pass
|
||||
|
||||
if user:
|
||||
entry = 'Channel deleted by @{1.name}#{1.discriminator}(id:{1.id}): "{0.name}" (id {0.id})'.format(channel, user)
|
||||
entry = 'Channel deleted by @{1.name}#{1.discriminator}(id:{1.id}): "{0.name}" (id {0.id})'.format(
|
||||
channel, user
|
||||
)
|
||||
else:
|
||||
entry = 'Channel deleted: "{0.name}" (id {0.id})'.format(channel)
|
||||
|
||||
|
@ -1552,19 +1573,25 @@ class ActivityLogger(commands.Cog):
|
|||
|
||||
if before.name != after.name:
|
||||
if user:
|
||||
entries.append('Channel rename by @{2.name}#{2.discriminator}(id:{2.id}): "{0.name}" (id {0.id}) renamed to "{1.name}"')
|
||||
entries.append(
|
||||
'Channel rename by @{2.name}#{2.discriminator}(id:{2.id}): "{0.name}" (id {0.id}) renamed to "{1.name}"'
|
||||
)
|
||||
else:
|
||||
entries.append('Channel rename: "{0.name}" (id {0.id}) renamed to "{1.name}"')
|
||||
|
||||
if before.topic != after.topic:
|
||||
if user:
|
||||
entries.append('Channel topic by @{2.name}#{2.discriminator}(id:{2.id}): "{0.name}" (id {0.id}) topic was set to "{1.topic}"')
|
||||
entries.append(
|
||||
'Channel topic by @{2.name}#{2.discriminator}(id:{2.id}): "{0.name}" (id {0.id}) topic was set to "{1.topic}"'
|
||||
)
|
||||
else:
|
||||
entries.append('Channel topic: "{0.name}" (id {0.id}) topic was set to "{1.topic}"')
|
||||
|
||||
if before.position != after.position:
|
||||
if user:
|
||||
entries.append('Channel position by @{2.name}#{2.discriminator}(id:{2.id}): "{0.name}" (id {0.id}) moved from {0.position} to {1.position}')
|
||||
entries.append(
|
||||
'Channel position by @{2.name}#{2.discriminator}(id:{2.id}): "{0.name}" (id {0.id}) moved from {0.position} to {1.position}'
|
||||
)
|
||||
else:
|
||||
entries.append('Channel position: "{0.name}" (id {0.id}) moved from {0.position} to {1.position}')
|
||||
|
||||
|
@ -1603,11 +1630,11 @@ class ActivityLogger(commands.Cog):
|
|||
msg = "Voice channel leave: {0} (id {0.id})"
|
||||
|
||||
async with self.config.member(member).stats() as stats:
|
||||
stats["vc_time_sec"] += (time.time() - stats["last_vc_time"])
|
||||
stats["vc_time_sec"] += time.time() - stats["last_vc_time"]
|
||||
stats["last_vc_time"] = None
|
||||
|
||||
if after.channel:
|
||||
msg += ' moving to {1.channel}'
|
||||
msg += " moving to {1.channel}"
|
||||
|
||||
await self.log(before.channel, msg.format(member, after))
|
||||
|
||||
|
@ -1618,35 +1645,35 @@ class ActivityLogger(commands.Cog):
|
|||
stats["last_vc_time"] = time.time()
|
||||
|
||||
if before.channel:
|
||||
msg += ', moved from {1.channel}'
|
||||
msg += ", moved from {1.channel}"
|
||||
|
||||
flags = self.get_voice_flags(after)
|
||||
|
||||
if flags:
|
||||
msg += ', flags: %s' % ','.join(flags)
|
||||
msg += ", flags: %s" % ",".join(flags)
|
||||
|
||||
await self.log(after.channel, msg.format(member, before))
|
||||
|
||||
if before.deaf != after.deaf:
|
||||
verb = 'deafen' if after.deaf else 'undeafen'
|
||||
await self.log(before.channel, 'guild {0}: {1} (id {1.id})'.format(verb, member))
|
||||
verb = "deafen" if after.deaf else "undeafen"
|
||||
await self.log(before.channel, "guild {0}: {1} (id {1.id})".format(verb, member))
|
||||
|
||||
if before.mute != after.mute:
|
||||
verb = 'mute' if after.mute else 'unmute'
|
||||
await self.log(before.channel, 'guild {0}: {1} (id {1.id})'.format(verb, member))
|
||||
verb = "mute" if after.mute else "unmute"
|
||||
await self.log(before.channel, "guild {0}: {1} (id {1.id})".format(verb, member))
|
||||
|
||||
if before.self_deaf != after.self_deaf:
|
||||
verb = 'deafen' if after.self_deaf else 'undeafen'
|
||||
await self.log(before.channel, 'guild self-{0}: {1} (id {1.id})'.format(verb, member))
|
||||
verb = "deafen" if after.self_deaf else "undeafen"
|
||||
await self.log(before.channel, "guild self-{0}: {1} (id {1.id})".format(verb, member))
|
||||
|
||||
if before.self_mute != after.self_mute:
|
||||
verb = 'mute' if after.self_mute else 'unmute'
|
||||
await self.log(before.channel, 'guild self-{0}: {1} (id {1.id})'.format(verb, member))
|
||||
verb = "mute" if after.self_mute else "unmute"
|
||||
await self.log(before.channel, "guild self-{0}: {1} (id {1.id})".format(verb, member))
|
||||
|
||||
if before.self_stream != after.self_stream:
|
||||
verb = 'stop-stream' if not after.self_stream else 'start-stream'
|
||||
await self.log(before.channel, 'guild self-{0}: {1} (id {1.id})'.format(verb, member))
|
||||
verb = "stop-stream" if not after.self_stream else "start-stream"
|
||||
await self.log(before.channel, "guild self-{0}: {1} (id {1.id})".format(verb, member))
|
||||
|
||||
if before.self_video != after.self_video:
|
||||
verb = 'start-video' if after.self_video else 'stop-video'
|
||||
await self.log(before.channel, 'guild self-{0}: {1} (id {1.id})'.format(verb, member))
|
||||
verb = "start-video" if after.self_video else "stop-video"
|
||||
await self.log(before.channel, "guild self-{0}: {1} (id {1.id})".format(verb, member))
|
||||
|
|
|
@ -43,7 +43,6 @@ def parse_time(datetimestring: str):
|
|||
return ret
|
||||
|
||||
|
||||
|
||||
def parse_time_naive(datetimestring: str):
|
||||
return parser.parse(datetimestring)
|
||||
|
||||
|
|
|
@ -59,9 +59,7 @@ class Admin(commands.Cog):
|
|||
self.conf.register_global(serverlocked=False)
|
||||
|
||||
self.conf.register_guild(
|
||||
announce_ignore=False,
|
||||
announce_channel=None, # Integer ID
|
||||
selfroles=[], # List of integer ID's
|
||||
announce_ignore=False, announce_channel=None, selfroles=[], # Integer ID # List of integer ID's
|
||||
)
|
||||
|
||||
self.__current_announcer = None
|
||||
|
@ -114,16 +112,12 @@ class Admin(commands.Cog):
|
|||
await member.add_roles(role)
|
||||
except discord.Forbidden:
|
||||
if not self.pass_hierarchy_check(ctx, role):
|
||||
await self.complain(
|
||||
ctx, T_(HIERARCHY_ISSUE), role=role, member=member, verb=_("add")
|
||||
)
|
||||
await self.complain(ctx, T_(HIERARCHY_ISSUE), role=role, member=member, verb=_("add"))
|
||||
else:
|
||||
await self.complain(ctx, T_(GENERIC_FORBIDDEN))
|
||||
else:
|
||||
await ctx.send(
|
||||
_("I successfully added {role.name} to {member.display_name}").format(
|
||||
role=role, member=member
|
||||
)
|
||||
_("I successfully added {role.name} to {member.display_name}").format(role=role, member=member)
|
||||
)
|
||||
|
||||
async def _removerole(self, ctx: commands.Context, member: discord.Member, role: discord.Role):
|
||||
|
@ -134,24 +128,18 @@ class Admin(commands.Cog):
|
|||
await member.remove_roles(role)
|
||||
except discord.Forbidden:
|
||||
if not self.pass_hierarchy_check(ctx, role):
|
||||
await self.complain(
|
||||
ctx, T_(HIERARCHY_ISSUE), role=role, member=member, verb=_("remove")
|
||||
)
|
||||
await self.complain(ctx, T_(HIERARCHY_ISSUE), role=role, member=member, verb=_("remove"))
|
||||
else:
|
||||
await self.complain(ctx, T_(GENERIC_FORBIDDEN))
|
||||
else:
|
||||
await ctx.send(
|
||||
_("I successfully removed {role.name} from {member.display_name}").format(
|
||||
role=role, member=member
|
||||
)
|
||||
_("I successfully removed {role.name} from {member.display_name}").format(role=role, member=member)
|
||||
)
|
||||
|
||||
@commands.command()
|
||||
@commands.guild_only()
|
||||
@checks.admin_or_permissions(manage_roles=True)
|
||||
async def addrole(
|
||||
self, ctx: commands.Context, rolename: discord.Role, *, user: MemberDefaultAuthor = None
|
||||
):
|
||||
async def addrole(self, ctx: commands.Context, rolename: discord.Role, *, user: MemberDefaultAuthor = None):
|
||||
"""Add a role to a user.
|
||||
|
||||
If user is left blank it defaults to the author of the command.
|
||||
|
@ -162,16 +150,12 @@ class Admin(commands.Cog):
|
|||
# noinspection PyTypeChecker
|
||||
await self._addrole(ctx, user, rolename)
|
||||
else:
|
||||
await self.complain(
|
||||
ctx, T_(USER_HIERARCHY_ISSUE), member=user, role=rolename, verb=_("add")
|
||||
)
|
||||
await self.complain(ctx, T_(USER_HIERARCHY_ISSUE), member=user, role=rolename, verb=_("add"))
|
||||
|
||||
@commands.command()
|
||||
@commands.guild_only()
|
||||
@checks.admin_or_permissions(manage_roles=True)
|
||||
async def removerole(
|
||||
self, ctx: commands.Context, rolename: discord.Role, *, user: MemberDefaultAuthor = None
|
||||
):
|
||||
async def removerole(self, ctx: commands.Context, rolename: discord.Role, *, user: MemberDefaultAuthor = None):
|
||||
"""Remove a role from a user.
|
||||
|
||||
If user is left blank it defaults to the author of the command.
|
||||
|
@ -182,9 +166,7 @@ class Admin(commands.Cog):
|
|||
# noinspection PyTypeChecker
|
||||
await self._removerole(ctx, user, rolename)
|
||||
else:
|
||||
await self.complain(
|
||||
ctx, T_(USER_HIERARCHY_ISSUE), member=user, role=rolename, verb=_("remove")
|
||||
)
|
||||
await self.complain(ctx, T_(USER_HIERARCHY_ISSUE), member=user, role=rolename, verb=_("remove"))
|
||||
|
||||
@commands.group()
|
||||
@commands.guild_only()
|
||||
|
@ -194,9 +176,7 @@ class Admin(commands.Cog):
|
|||
pass
|
||||
|
||||
@editrole.command(name="colour", aliases=["color"])
|
||||
async def editrole_colour(
|
||||
self, ctx: commands.Context, role: discord.Role, value: discord.Colour
|
||||
):
|
||||
async def editrole_colour(self, ctx: commands.Context, role: discord.Role, value: discord.Colour):
|
||||
"""Edit a role's colour.
|
||||
|
||||
Use double quotes if the role contains spaces.
|
||||
|
@ -234,9 +214,7 @@ class Admin(commands.Cog):
|
|||
"""
|
||||
author = ctx.message.author
|
||||
old_name = role.name
|
||||
reason = "{}({}) changed the name of role '{}' to '{}'".format(
|
||||
author.name, author.id, old_name, name
|
||||
)
|
||||
reason = "{}({}) changed the name of role '{}' to '{}'".format(author.name, author.id, old_name, name)
|
||||
|
||||
if not self.pass_user_hierarchy_check(ctx, role):
|
||||
await self.complain(ctx, T_(ROLE_USER_HIERARCHY_ISSUE), role=role)
|
||||
|
@ -285,9 +263,7 @@ class Admin(commands.Cog):
|
|||
channel = ctx.channel
|
||||
await self.conf.guild(ctx.guild).announce_channel.set(channel.id)
|
||||
|
||||
await ctx.send(
|
||||
_("The announcement channel has been set to {channel.mention}").format(channel=channel)
|
||||
)
|
||||
await ctx.send(_("The announcement channel has been set to {channel.mention}").format(channel=channel))
|
||||
|
||||
@announce.command(name="ignore")
|
||||
@commands.guild_only()
|
||||
|
@ -298,15 +274,9 @@ class Admin(commands.Cog):
|
|||
await self.conf.guild(ctx.guild).announce_ignore.set(not ignored)
|
||||
|
||||
if ignored: # Keeping original logic....
|
||||
await ctx.send(
|
||||
_("The server {guild.name} will receive announcements.").format(guild=ctx.guild)
|
||||
)
|
||||
await ctx.send(_("The server {guild.name} will receive announcements.").format(guild=ctx.guild))
|
||||
else:
|
||||
await ctx.send(
|
||||
_("The server {guild.name} will not receive announcements.").format(
|
||||
guild=ctx.guild
|
||||
)
|
||||
)
|
||||
await ctx.send(_("The server {guild.name} will not receive announcements.").format(guild=ctx.guild))
|
||||
|
||||
async def _valid_selfroles(self, guild: discord.Guild) -> Tuple[discord.Role]:
|
||||
"""
|
||||
|
|
|
@ -66,9 +66,7 @@ class Announcer:
|
|||
try:
|
||||
await channel.send(self.message)
|
||||
except discord.Forbidden:
|
||||
await bot_owner.send(
|
||||
_("I could not announce to server: {server.id}").format(server=g)
|
||||
)
|
||||
await bot_owner.send(_("I could not announce to server: {server.id}").format(server=g))
|
||||
await asyncio.sleep(0.5)
|
||||
|
||||
self.active = False
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from .events import Events
|
||||
|
||||
|
||||
def setup(bot):
|
||||
n = Events(bot)
|
||||
bot.add_cog(n)
|
||||
|
|
|
@ -11,11 +11,30 @@ import pytz
|
|||
from tzlocal import get_localzone
|
||||
|
||||
|
||||
basic_colors = [discord.Colour.blue(), discord.Colour.teal(), discord.Colour.dark_teal(), discord.Colour.green(), discord.Colour.dark_green(), discord.Colour.dark_blue(), discord.Colour.purple(), discord.Colour.dark_purple(), discord.Colour.magenta(), discord.Colour.gold(), discord.Colour.orange(), discord.Colour.red(), discord.Colour.dark_red(), discord.Colour.blurple(), discord.Colour.greyple()]
|
||||
basic_colors = [
|
||||
discord.Colour.blue(),
|
||||
discord.Colour.teal(),
|
||||
discord.Colour.dark_teal(),
|
||||
discord.Colour.green(),
|
||||
discord.Colour.dark_green(),
|
||||
discord.Colour.dark_blue(),
|
||||
discord.Colour.purple(),
|
||||
discord.Colour.dark_purple(),
|
||||
discord.Colour.magenta(),
|
||||
discord.Colour.gold(),
|
||||
discord.Colour.orange(),
|
||||
discord.Colour.red(),
|
||||
discord.Colour.dark_red(),
|
||||
discord.Colour.blurple(),
|
||||
discord.Colour.greyple(),
|
||||
]
|
||||
|
||||
|
||||
class Events(commands.Cog):
|
||||
"""
|
||||
Set events that track time since set events
|
||||
"""
|
||||
|
||||
def __init__(self, bot):
|
||||
super().__init__()
|
||||
self.config = Config.get_conf(self, identifier=6748392754)
|
||||
|
@ -55,18 +74,33 @@ class Events(commands.Cog):
|
|||
|
||||
elapsed_time = datetime.datetime.utcnow() - start_time
|
||||
embed = discord.Embed(title=event_name, colour=random.choice(basic_colors))
|
||||
embed.add_field(name="Event time", value=start_time.replace(tzinfo=pytz.utc).astimezone(self.timezone).strftime("%b %d, %Y, %H:%M"))
|
||||
embed.add_field(
|
||||
name="Event time",
|
||||
value=start_time.replace(tzinfo=pytz.utc).astimezone(self.timezone).strftime("%b %d, %Y, %H:%M"),
|
||||
)
|
||||
day_msg = "{} day{},".format(elapsed_time.days, "s" if elapsed_time.days > 1 else "")
|
||||
hour_msg = " {} hour{}".format(int(elapsed_time.seconds / 60 / 60), "s" if int(elapsed_time.seconds / 60 / 60) > 1 else "")
|
||||
hour_msg = " {} hour{}".format(
|
||||
int(elapsed_time.seconds / 60 / 60), "s" if int(elapsed_time.seconds / 60 / 60) > 1 else ""
|
||||
)
|
||||
if elapsed_time.days > 0 or int(elapsed_time.seconds / 60 / 60) > 0:
|
||||
minute_msg = ", and {} minute{}".format(int(elapsed_time.seconds / 60 - int(elapsed_time.seconds / 60 / 60) * 60), "s" if int(elapsed_time.seconds / 60 - int(elapsed_time.seconds / 60 / 60) * 60) > 1 else "")
|
||||
minute_msg = ", and {} minute{}".format(
|
||||
int(elapsed_time.seconds / 60 - int(elapsed_time.seconds / 60 / 60) * 60),
|
||||
"s" if int(elapsed_time.seconds / 60 - int(elapsed_time.seconds / 60 / 60) * 60) > 1 else "",
|
||||
)
|
||||
else:
|
||||
minute_msg = "{} minute{}".format(int(elapsed_time.seconds / 60 - int(elapsed_time.seconds / 60 / 60) * 60), "s" if int(elapsed_time.seconds / 60 - int(elapsed_time.seconds / 60 / 60) * 60) > 1 else "")
|
||||
msg = "{}{}{}".format(day_msg if elapsed_time.days > 0 else "", hour_msg if int(elapsed_time.seconds / 60 / 60) > 0 else "", minute_msg)
|
||||
minute_msg = "{} minute{}".format(
|
||||
int(elapsed_time.seconds / 60 - int(elapsed_time.seconds / 60 / 60) * 60),
|
||||
"s" if int(elapsed_time.seconds / 60 - int(elapsed_time.seconds / 60 / 60) * 60) > 1 else "",
|
||||
)
|
||||
msg = "{}{}{}".format(
|
||||
day_msg if elapsed_time.days > 0 else "",
|
||||
hour_msg if int(elapsed_time.seconds / 60 / 60) > 0 else "",
|
||||
minute_msg,
|
||||
)
|
||||
embed.add_field(name="Elapsed time", value=msg)
|
||||
message = await channel.send(embed=embed)
|
||||
async with self.config.guild(guild).events() as events:
|
||||
new_event = {"start_time" : int(start_time.replace(tzinfo=pytz.utc).timestamp()), "name" : event_name}
|
||||
new_event = {"start_time": int(start_time.replace(tzinfo=pytz.utc).timestamp()), "name": event_name}
|
||||
events[message.id] = new_event
|
||||
await ctx.send("Event added!")
|
||||
|
||||
|
@ -98,13 +132,20 @@ class Events(commands.Cog):
|
|||
msg += "```"
|
||||
await ctx.send(msg)
|
||||
await ctx.send("Please choose which event you want to delete. (type number in chat)")
|
||||
|
||||
def m_check(m):
|
||||
try:
|
||||
return m.author.id == ctx.author.id and m.channel.id == ctx.channel.id and int(m.content) <= counter and int(m.content) >= 0
|
||||
return (
|
||||
m.author.id == ctx.author.id
|
||||
and m.channel.id == ctx.channel.id
|
||||
and int(m.content) <= counter
|
||||
and int(m.content) >= 0
|
||||
)
|
||||
except:
|
||||
return False
|
||||
|
||||
try:
|
||||
response = await self.bot.wait_for('message', timeout=30, check=m_check)
|
||||
response = await self.bot.wait_for("message", timeout=30, check=m_check)
|
||||
except:
|
||||
await ctx.send("Timed out, event deletion cancelled.")
|
||||
return
|
||||
|
@ -179,14 +220,35 @@ class Events(commands.Cog):
|
|||
elapsed_time = datetime.datetime.utcnow() - start_time
|
||||
embed = message.embeds[0]
|
||||
embed.clear_fields()
|
||||
embed.add_field(name="Event time", value=start_time.replace(tzinfo=pytz.utc).astimezone(self.timezone).strftime("%b %d, %Y, %H:%M"))
|
||||
embed.add_field(
|
||||
name="Event time",
|
||||
value=start_time.replace(tzinfo=pytz.utc)
|
||||
.astimezone(self.timezone)
|
||||
.strftime("%b %d, %Y, %H:%M"),
|
||||
)
|
||||
day_msg = "{} day{},".format(elapsed_time.days, "s" if elapsed_time.days > 1 else "")
|
||||
hour_msg = " {} hour{}".format(int(elapsed_time.seconds / 60 / 60), "s" if int(elapsed_time.seconds / 60 / 60) > 1 else "")
|
||||
hour_msg = " {} hour{}".format(
|
||||
int(elapsed_time.seconds / 60 / 60), "s" if int(elapsed_time.seconds / 60 / 60) > 1 else ""
|
||||
)
|
||||
if elapsed_time.days > 0 or int(elapsed_time.seconds / 60 / 60) > 0:
|
||||
minute_msg = ", and {} minute{}".format(int(elapsed_time.seconds / 60 - int(elapsed_time.seconds / 60 / 60) * 60), "s" if int(elapsed_time.seconds / 60 - int(elapsed_time.seconds / 60 / 60) * 60) > 1 else "")
|
||||
minute_msg = ", and {} minute{}".format(
|
||||
int(elapsed_time.seconds / 60 - int(elapsed_time.seconds / 60 / 60) * 60),
|
||||
"s"
|
||||
if int(elapsed_time.seconds / 60 - int(elapsed_time.seconds / 60 / 60) * 60) > 1
|
||||
else "",
|
||||
)
|
||||
else:
|
||||
minute_msg = "{} minute{}".format(int(elapsed_time.seconds / 60 - int(elapsed_time.seconds / 60 / 60) * 60), "s" if int(elapsed_time.seconds / 60 - int(elapsed_time.seconds / 60 / 60) * 60) > 1 else "")
|
||||
msg = "{}{}{}".format(day_msg if elapsed_time.days > 0 else "", hour_msg if int(elapsed_time.seconds / 60 / 60) > 0 else "", minute_msg)
|
||||
minute_msg = "{} minute{}".format(
|
||||
int(elapsed_time.seconds / 60 - int(elapsed_time.seconds / 60 / 60) * 60),
|
||||
"s"
|
||||
if int(elapsed_time.seconds / 60 - int(elapsed_time.seconds / 60 / 60) * 60) > 1
|
||||
else "",
|
||||
)
|
||||
msg = "{}{}{}".format(
|
||||
day_msg if elapsed_time.days > 0 else "",
|
||||
hour_msg if int(elapsed_time.seconds / 60 / 60) > 0 else "",
|
||||
minute_msg,
|
||||
)
|
||||
embed.add_field(name="Elapsed time", value=msg)
|
||||
await message.edit(embed=embed)
|
||||
await asyncio.sleep(30)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from .pony import Pony
|
||||
|
||||
|
||||
def setup(bot):
|
||||
bot.add_cog(Pony())
|
||||
|
|
70
pony/pony.py
70
pony/pony.py
|
@ -7,18 +7,14 @@ import os
|
|||
import traceback
|
||||
import json
|
||||
|
||||
|
||||
class Pony(commands.Cog):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
self.config = Config.get_conf(self, identifier=7384662719)
|
||||
default_global = {
|
||||
"maxfilters":50
|
||||
}
|
||||
self.default_guild = {
|
||||
"filters": ["-meme", "safe", "-spoiler:*", "-vulgar"],
|
||||
"verbose": False
|
||||
}
|
||||
default_global = {"maxfilters": 50}
|
||||
self.default_guild = {"filters": ["-meme", "safe", "-spoiler:*", "-vulgar"], "verbose": False}
|
||||
self.config.register_guild(**self.default_guild)
|
||||
self.config.register_global(**default_global)
|
||||
|
||||
|
@ -40,7 +36,7 @@ class Pony(commands.Cog):
|
|||
"""
|
||||
Gives a random picture of our mascot!
|
||||
"""
|
||||
await fetch_image(self, ctx, randomize=True, mascot=True, tags=['safe,', 'coe'])
|
||||
await fetch_image(self, ctx, randomize=True, mascot=True, tags=["safe,", "coe"])
|
||||
|
||||
@commands.group()
|
||||
@commands.guild_only()
|
||||
|
@ -53,7 +49,7 @@ class Pony(commands.Cog):
|
|||
pass
|
||||
|
||||
@ponyfilter.command(name="add")
|
||||
async def _add_ponyfilter(self, ctx, filter_tag : str):
|
||||
async def _add_ponyfilter(self, ctx, filter_tag: str):
|
||||
"""Adds a tag to the server's pony filter list
|
||||
|
||||
Example: !ponyfilter add safe"""
|
||||
|
@ -72,7 +68,7 @@ class Pony(commands.Cog):
|
|||
await ctx.send("This server has exceeded the maximum filters ({}/{}).".format(len(filters), max_filters))
|
||||
|
||||
@ponyfilter.command(name="del")
|
||||
async def _del_ponyfilter(self, ctx, filter_tag : str=""):
|
||||
async def _del_ponyfilter(self, ctx, filter_tag: str = ""):
|
||||
"""Deletes a tag from the server's pony filter list
|
||||
|
||||
Without arguments, reverts to the default pony filter list
|
||||
|
@ -100,10 +96,10 @@ class Pony(commands.Cog):
|
|||
guild = ctx.guild
|
||||
filters = await self.config.guild(guild).filters()
|
||||
if filters:
|
||||
filter_list = '\n'.join(sorted(filters))
|
||||
filter_list = "\n".join(sorted(filters))
|
||||
target_guild = "{}'s".format(guild.name)
|
||||
else:
|
||||
filter_list = '\n'.join(sorted(filters["default"]))
|
||||
filter_list = "\n".join(sorted(filters["default"]))
|
||||
target_guild = "Default"
|
||||
await ctx.send("{} pony filter list contains:```\n{}```".format(target_guild, filter_list))
|
||||
|
||||
|
@ -114,7 +110,7 @@ class Pony(commands.Cog):
|
|||
pass
|
||||
|
||||
@ponyset.command(name="verbose")
|
||||
async def _verbose_ponyset(self, ctx, toggle : str="toggle"):
|
||||
async def _verbose_ponyset(self, ctx, toggle: str = "toggle"):
|
||||
"""Toggles verbose mode"""
|
||||
guild = ctx.guild
|
||||
verbose = await self.config.guild(guild).verbose()
|
||||
|
@ -140,7 +136,7 @@ class Pony(commands.Cog):
|
|||
|
||||
@ponyset.command(name="maxfilters")
|
||||
@checks.is_owner()
|
||||
async def _maxfilters_ponyset(self, ctx, new_max_filters : int):
|
||||
async def _maxfilters_ponyset(self, ctx, new_max_filters: int):
|
||||
"""Sets the global tag limit for the filter list.
|
||||
|
||||
Leave blank to get current max filters.
|
||||
|
@ -178,7 +174,7 @@ class Pony(commands.Cog):
|
|||
if guild is None:
|
||||
continue
|
||||
|
||||
await self.config.guild(guild).verbose.set(json_guild_verbose['verbose'])
|
||||
await self.config.guild(guild).verbose.set(json_guild_verbose["verbose"])
|
||||
msg += "**{}**\n".format(guild)
|
||||
if len(msg) + 100 > 2000:
|
||||
await ctx.send(msg)
|
||||
|
@ -194,7 +190,7 @@ class Pony(commands.Cog):
|
|||
for json_guild_id, json_guild_filters in import_filters.items():
|
||||
if json_guild_id != "default":
|
||||
|
||||
guild = bot.get_guild(int(json_guild_id)) # returns None if guild is not found
|
||||
guild = bot.get_guild(int(json_guild_id)) # returns None if guild is not found
|
||||
if guild is None:
|
||||
continue
|
||||
|
||||
|
@ -204,7 +200,7 @@ class Pony(commands.Cog):
|
|||
await ctx.send(msg)
|
||||
msg = ""
|
||||
else:
|
||||
continue
|
||||
continue
|
||||
if msg != "":
|
||||
await ctx.send(msg)
|
||||
|
||||
|
@ -213,25 +209,25 @@ class Pony(commands.Cog):
|
|||
except json.decoder.JSONDecodeError:
|
||||
await ctx.send("Invalid or malformed json files.")
|
||||
|
||||
async def fetch_image(self, ctx, randomize : bool=False, tags : list=[], mascot=False):
|
||||
async def fetch_image(self, ctx, randomize: bool = False, tags: list = [], mascot=False):
|
||||
guild = ctx.guild
|
||||
filters = await self.config.guild(guild).filters()
|
||||
verbose = await self.config.guild(guild).verbose()
|
||||
|
||||
#Initialize variables
|
||||
artist = "unknown artist"
|
||||
artists = ""
|
||||
artistList = []
|
||||
embedLink = ""
|
||||
embedTitle = ""
|
||||
imageId = ""
|
||||
message = ""
|
||||
output = None
|
||||
rating = ""
|
||||
# Initialize variables
|
||||
artist = "unknown artist"
|
||||
artists = ""
|
||||
artistList = []
|
||||
embedLink = ""
|
||||
embedTitle = ""
|
||||
imageId = ""
|
||||
message = ""
|
||||
output = None
|
||||
rating = ""
|
||||
ratingColor = "FFFFFF"
|
||||
ratingWord = "unknown"
|
||||
search = "https://derpibooru.org/search.json?q="
|
||||
tagSearch = ""
|
||||
ratingWord = "unknown"
|
||||
search = "https://derpibooru.org/search.json?q="
|
||||
tagSearch = ""
|
||||
|
||||
# Assign tags to URL
|
||||
if tags:
|
||||
|
@ -250,12 +246,12 @@ class Pony(commands.Cog):
|
|||
# Randomize results and apply Derpibooru's "Everything" filter
|
||||
if randomize:
|
||||
if not tags and filters:
|
||||
if filters == []:
|
||||
search = "https://derpibooru.org/images/random.json?filter_id=56027"
|
||||
else:
|
||||
search += "&random_image=y&filter_id=56027"
|
||||
if filters == []:
|
||||
search = "https://derpibooru.org/images/random.json?filter_id=56027"
|
||||
else:
|
||||
search += "&random_image=y&filter_id=56027"
|
||||
else:
|
||||
search += "&random_image=y&filter_id=56027"
|
||||
search += "&random_image=y&filter_id=56027"
|
||||
|
||||
# Inform users about image retrieving
|
||||
message = await ctx.send("Fetching pony image...")
|
||||
|
@ -263,7 +259,7 @@ class Pony(commands.Cog):
|
|||
# Fetch the image or display an error
|
||||
try:
|
||||
async with aiohttp.ClientSession(loop=ctx.bot.loop) as session:
|
||||
async with session.get(search, headers={'User-Agent': "Booru-Cogs (https://git.io/booru)"}) as r:
|
||||
async with session.get(search, headers={"User-Agent": "Booru-Cogs (https://git.io/booru)"}) as r:
|
||||
website = await r.json()
|
||||
if randomize:
|
||||
if "id" in website:
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from .punish import Punish
|
||||
|
||||
|
||||
async def setup(bot):
|
||||
punish = Punish(bot)
|
||||
await punish.initialize()
|
||||
|
|
|
@ -2,7 +2,8 @@ class Memoizer:
|
|||
"""
|
||||
General purpose cache for function results. Appends positional args, overlays kwargs. Both must be hashable.
|
||||
"""
|
||||
__slots__ = ['_cache', '_func', '_args', '_kwargs']
|
||||
|
||||
__slots__ = ["_cache", "_func", "_args", "_kwargs"]
|
||||
|
||||
def __init__(self, func, *args, **kwargs):
|
||||
self._cache = {}
|
||||
|
|
395
punish/punish.py
395
punish/punish.py
|
@ -16,21 +16,22 @@ import logging
|
|||
import time
|
||||
import textwrap
|
||||
|
||||
log = logging.getLogger('red.punish')
|
||||
log = logging.getLogger("red.punish")
|
||||
|
||||
__version__ = '3.0.0'
|
||||
__version__ = "3.0.0"
|
||||
|
||||
PURGE_MESSAGES = 1 # for cpunish
|
||||
|
||||
DEFAULT_ROLE_NAME = 'Punished'
|
||||
DEFAULT_ROLE_NAME = "Punished"
|
||||
DEFAULT_TEXT_OVERWRITE = discord.PermissionOverwrite(send_messages=False, send_tts_messages=False, add_reactions=False)
|
||||
DEFAULT_VOICE_OVERWRITE = discord.PermissionOverwrite(speak=False, connect=False)
|
||||
DEFAULT_TIMEOUT_OVERWRITE = discord.PermissionOverwrite(send_messages=True, read_messages=True)
|
||||
|
||||
QUEUE_TIME_CUTOFF = 30
|
||||
|
||||
DEFAULT_TIMEOUT = '5m'
|
||||
DEFAULT_CASE_MIN_LENGTH = '5m' # only create modlog cases when length is longer than this
|
||||
DEFAULT_TIMEOUT = "5m"
|
||||
DEFAULT_CASE_MIN_LENGTH = "5m" # only create modlog cases when length is longer than this
|
||||
|
||||
|
||||
class Punish(commands.Cog):
|
||||
"""
|
||||
|
@ -38,6 +39,7 @@ class Punish(commands.Cog):
|
|||
do other things that can be denied using discord permissions. Includes
|
||||
auto-setup and more.
|
||||
"""
|
||||
|
||||
def __init__(self, bot):
|
||||
super().__init__()
|
||||
|
||||
|
@ -53,7 +55,7 @@ class Punish(commands.Cog):
|
|||
"VOICE_OVERWRITE": overwrite_to_dict(DEFAULT_VOICE_OVERWRITE),
|
||||
"ROLE_ID": None,
|
||||
"NITRO_ID": None,
|
||||
"CHANNEL_ID": None
|
||||
"CHANNEL_ID": None,
|
||||
}
|
||||
self.config.register_guild(**default_guild)
|
||||
|
||||
|
@ -100,7 +102,7 @@ class Punish(commands.Cog):
|
|||
elif user:
|
||||
await self._punish_cmd_common(ctx, user, duration, reason)
|
||||
|
||||
@punish.command(name='cstart')
|
||||
@punish.command(name="cstart")
|
||||
@commands.guild_only()
|
||||
@checks.mod()
|
||||
async def punish_cstart(self, ctx, user: discord.Member, duration: str = None, *, reason: str = None):
|
||||
|
@ -121,7 +123,7 @@ class Punish(commands.Cog):
|
|||
except discord.errors.Forbidden:
|
||||
await ctx.send("Punishment set, but I need permissions to manage messages to clean up.")
|
||||
|
||||
@punish.command(name='list')
|
||||
@punish.command(name="list")
|
||||
@commands.guild_only()
|
||||
@checks.mod()
|
||||
async def punish_list(self, ctx):
|
||||
|
@ -135,7 +137,7 @@ class Punish(commands.Cog):
|
|||
guild = ctx.guild
|
||||
guild_id = guild.id
|
||||
now = time.time()
|
||||
headers = ['Member', 'Remaining', 'Moderator', 'Reason']
|
||||
headers = ["Member", "Remaining", "Moderator", "Reason"]
|
||||
punished = await self.config.guild(guild).PUNISHED()
|
||||
|
||||
embeds = []
|
||||
|
@ -143,13 +145,13 @@ class Punish(commands.Cog):
|
|||
for i, data in enumerate(punished.items()):
|
||||
member_id, data = data
|
||||
member_name = getmname(member_id, guild)
|
||||
moderator = getmname(data['by'], guild)
|
||||
reason = data['reason']
|
||||
until = data['until']
|
||||
moderator = getmname(data["by"], guild)
|
||||
reason = data["reason"]
|
||||
until = data["until"]
|
||||
sort = until or float("inf")
|
||||
remaining = generate_timespec(until - now, short=True) if until else 'forever'
|
||||
remaining = generate_timespec(until - now, short=True) if until else "forever"
|
||||
|
||||
row = [member_name, remaining, moderator, reason or 'No reason set.']
|
||||
row = [member_name, remaining, moderator, reason or "No reason set."]
|
||||
embed = discord.Embed(title="Punish List", colour=discord.Colour.from_rgb(255, 0, 0))
|
||||
|
||||
for header, row_val in zip(headers, row):
|
||||
|
@ -164,7 +166,7 @@ class Punish(commands.Cog):
|
|||
|
||||
await menu(ctx, embeds, DEFAULT_CONTROLS)
|
||||
|
||||
@punish.command(name='clean')
|
||||
@punish.command(name="clean")
|
||||
@commands.guild_only()
|
||||
@checks.mod()
|
||||
async def punish_clean(self, ctx, clean_pending: bool = False):
|
||||
|
@ -189,14 +191,14 @@ class Punish(commands.Cog):
|
|||
if not mid.isdigit() or guild.get_member(mid):
|
||||
continue
|
||||
|
||||
elif clean_pending or ((mdata['until'] or 0) < now):
|
||||
del(data[mid])
|
||||
elif clean_pending or ((mdata["until"] or 0) < now):
|
||||
del data[mid]
|
||||
count += 1
|
||||
|
||||
await self.config.guild(guild).PUNISHED.set(data)
|
||||
await ctx.send('Cleaned %i absent members from the list.' % count)
|
||||
await ctx.send("Cleaned %i absent members from the list." % count)
|
||||
|
||||
@punish.command(name='clean-bans')
|
||||
@punish.command(name="clean-bans")
|
||||
@commands.guild_only()
|
||||
@checks.mod()
|
||||
async def punish_clean_bans(self, ctx):
|
||||
|
@ -220,13 +222,13 @@ class Punish(commands.Cog):
|
|||
continue
|
||||
|
||||
elif mid in ban_ids:
|
||||
del(data[mid])
|
||||
del data[mid]
|
||||
count += 1
|
||||
|
||||
await self.config.guild(guild).PUNISHED.set(data)
|
||||
await ctx.send('Cleaned %i banned users from the list.' % count)
|
||||
await ctx.send("Cleaned %i banned users from the list." % count)
|
||||
|
||||
@punish.command(name='warn')
|
||||
@punish.command(name="warn")
|
||||
@commands.guild_only()
|
||||
@checks.mod_or_permissions(manage_messages=True)
|
||||
async def punish_warn(self, ctx, user: discord.Member, *, reason: str = None):
|
||||
|
@ -234,16 +236,15 @@ class Punish(commands.Cog):
|
|||
Warns a user with boilerplate about the rules
|
||||
"""
|
||||
|
||||
msg = ['Hey %s, ' % user.mention]
|
||||
msg.append("you're doing something that might get you muted if you keep "
|
||||
"doing it.")
|
||||
msg = ["Hey %s, " % user.mention]
|
||||
msg.append("you're doing something that might get you muted if you keep " "doing it.")
|
||||
if reason:
|
||||
msg.append(" Specifically, %s." % reason)
|
||||
|
||||
msg.append("Be sure to review the guild rules.")
|
||||
await ctx.send(' '.join(msg))
|
||||
await ctx.send(" ".join(msg))
|
||||
|
||||
@punish.command(name='end', aliases=['remove'])
|
||||
@punish.command(name="end", aliases=["remove"])
|
||||
@commands.guild_only()
|
||||
@checks.mod()
|
||||
async def punish_end(self, ctx, user: discord.Member, *, reason: str = None):
|
||||
|
@ -260,60 +261,64 @@ class Punish(commands.Cog):
|
|||
now = time.time()
|
||||
punished = await self.config.guild(guild).PUNISHED()
|
||||
data = punished.get(str(user.id), {})
|
||||
removed_roles_parsed = resolve_role_list(guild, data.get('removed_roles', []))
|
||||
removed_roles_parsed = resolve_role_list(guild, data.get("removed_roles", []))
|
||||
|
||||
if role and role in user.roles:
|
||||
msg = 'Punishment manually ended early by %s.' % ctx.author
|
||||
msg = "Punishment manually ended early by %s." % ctx.author
|
||||
|
||||
original_start = data.get('start')
|
||||
original_end = data.get('until')
|
||||
original_start = data.get("start")
|
||||
original_end = data.get("until")
|
||||
remaining = original_end and (original_end - now)
|
||||
|
||||
if remaining:
|
||||
msg += ' %s was left' % generate_timespec(round(remaining))
|
||||
msg += " %s was left" % generate_timespec(round(remaining))
|
||||
|
||||
if original_start:
|
||||
msg += ' of the original %s.' % generate_timespec(round(original_end - original_start))
|
||||
msg += " of the original %s." % generate_timespec(round(original_end - original_start))
|
||||
else:
|
||||
msg += '.'
|
||||
msg += "."
|
||||
|
||||
if reason:
|
||||
msg += '\n\nReason for ending early: ' + reason
|
||||
msg += "\n\nReason for ending early: " + reason
|
||||
|
||||
if data.get('reason'):
|
||||
msg += '\n\nOriginal reason was: ' + data['reason']
|
||||
if data.get("reason"):
|
||||
msg += "\n\nOriginal reason was: " + data["reason"]
|
||||
|
||||
updated_reason = str(msg) # copy string
|
||||
updated_reason = str(msg) # copy string
|
||||
|
||||
if removed_roles_parsed:
|
||||
names_list = format_list(*(r.name for r in removed_roles_parsed))
|
||||
msg += "\nRestored role(s): {}".format(names_list)
|
||||
|
||||
if not await self._unpunish(user, reason=updated_reason, update=True, moderator=moderator):
|
||||
msg += '\n\n(failed to send punishment end notification DM)'
|
||||
msg += "\n\n(failed to send punishment end notification DM)"
|
||||
|
||||
await ctx.send(msg)
|
||||
elif data: # This shouldn't happen, but just in case
|
||||
now = time.time()
|
||||
until = data.get('until')
|
||||
remaining = until and generate_timespec(round(until - now)) or 'forever'
|
||||
until = data.get("until")
|
||||
remaining = until and generate_timespec(round(until - now)) or "forever"
|
||||
|
||||
data_fmt = '\n'.join([
|
||||
"**Reason:** %s" % (data.get('reason') or 'no reason set'),
|
||||
"**Time remaining:** %s" % remaining,
|
||||
"**Moderator**: %s" % (user.guild.get_member(data.get('by')) or 'Missing ID#%s' % data.get('by'))
|
||||
])
|
||||
del(punished[str(user.id)])
|
||||
data_fmt = "\n".join(
|
||||
[
|
||||
"**Reason:** %s" % (data.get("reason") or "no reason set"),
|
||||
"**Time remaining:** %s" % remaining,
|
||||
"**Moderator**: %s" % (user.guild.get_member(data.get("by")) or "Missing ID#%s" % data.get("by")),
|
||||
]
|
||||
)
|
||||
del punished[str(user.id)]
|
||||
await self.config.guild(guild).PUNISHED.set(punished)
|
||||
|
||||
await ctx.send("That user doesn't have the %s role, but they still have a data entry. I removed it, "
|
||||
"but in case it's needed, this is what was there:\n\n%s" % (role.name, data_fmt))
|
||||
await ctx.send(
|
||||
"That user doesn't have the %s role, but they still have a data entry. I removed it, "
|
||||
"but in case it's needed, this is what was there:\n\n%s" % (role.name, data_fmt)
|
||||
)
|
||||
elif role:
|
||||
await ctx.send("That user doesn't have the %s role." % role.name)
|
||||
else:
|
||||
await ctx.send("The punish role couldn't be found in this guild.")
|
||||
|
||||
@punish.command(name='reason')
|
||||
@punish.command(name="reason")
|
||||
@commands.guild_only()
|
||||
@checks.mod()
|
||||
async def punish_reason(self, ctx, user: discord.Member, *, reason: str = None):
|
||||
|
@ -325,19 +330,21 @@ class Punish(commands.Cog):
|
|||
data = punished.get(str(user.id), None)
|
||||
|
||||
if not data:
|
||||
await ctx.send("That user doesn't have an active punishment entry. To update modlog "
|
||||
"cases manually, use the `%sreason` command." % ctx.prefix)
|
||||
await ctx.send(
|
||||
"That user doesn't have an active punishment entry. To update modlog "
|
||||
"cases manually, use the `%sreason` command." % ctx.prefix
|
||||
)
|
||||
return
|
||||
|
||||
punished[str(user.id)]['reason'] = reason
|
||||
punished[str(user.id)]["reason"] = reason
|
||||
await self.config.guild(guild).PUNISHED.set(punished)
|
||||
|
||||
if reason:
|
||||
msg = 'Reason updated.'
|
||||
msg = "Reason updated."
|
||||
else:
|
||||
msg = 'Reason cleared.'
|
||||
msg = "Reason cleared."
|
||||
|
||||
caseno = data.get('caseno')
|
||||
caseno = data.get("caseno")
|
||||
try:
|
||||
case = await modlog.get_case(caseno, guild, self.bot)
|
||||
except:
|
||||
|
@ -348,12 +355,12 @@ class Punish(commands.Cog):
|
|||
moderator = ctx.author
|
||||
|
||||
try:
|
||||
edits = {'reason': reason}
|
||||
edits = {"reason": reason}
|
||||
|
||||
if moderator.id != data.get('by'):
|
||||
edits['amended_by'] = moderator
|
||||
if moderator.id != data.get("by"):
|
||||
edits["amended_by"] = moderator
|
||||
|
||||
edits['modified_at'] = ctx.message.created_at.timestamp()
|
||||
edits["modified_at"] = ctx.message.created_at.timestamp()
|
||||
|
||||
await case.edit(edits)
|
||||
except:
|
||||
|
@ -504,23 +511,23 @@ class Punish(commands.Cog):
|
|||
|
||||
try:
|
||||
# Combine sets to get the baseline (roles they'd have normally)
|
||||
member_roles |= set(role_memo.filter(member_data['removed_roles'], skip_nulls=True))
|
||||
member_roles |= set(role_memo.filter(member_data["removed_roles"], skip_nulls=True))
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
# update new removed roles with intersection of guild removal list and baseline
|
||||
new_removed = guild_remove_roles & member_roles
|
||||
punished[str(member.id)]['removed_roles'] = [r.id for r in new_removed]
|
||||
punished[str(member.id)]["removed_roles"] = [r.id for r in new_removed]
|
||||
|
||||
member_roles -= guild_remove_roles
|
||||
|
||||
# can't restore, so skip (remove from set)
|
||||
for role in (member_roles - original_roles):
|
||||
for role in member_roles - original_roles:
|
||||
if role >= highest_role:
|
||||
member_roles.discard(role)
|
||||
|
||||
# can't remove, so skip (re-add to set)
|
||||
for role in (original_roles - member_roles):
|
||||
for role in original_roles - member_roles:
|
||||
if role >= highest_role:
|
||||
member_roles.add(role)
|
||||
|
||||
|
@ -541,7 +548,7 @@ class Punish(commands.Cog):
|
|||
|
||||
await ctx.send(msg)
|
||||
|
||||
@punishset.command(name='setup')
|
||||
@punishset.command(name="setup")
|
||||
async def punishset_setup(self, ctx):
|
||||
"""
|
||||
(Re)configures the punish role and channel overrides
|
||||
|
@ -568,28 +575,29 @@ class Punish(commands.Cog):
|
|||
perms = discord.Permissions.none()
|
||||
role = await guild.create_role(name=default_name, permissions=perms, reason="punish cog.")
|
||||
else:
|
||||
msgobj = await ctx.send('%s role exists... ' % role.name)
|
||||
msgobj = await ctx.send("%s role exists... " % role.name)
|
||||
|
||||
if role.position != (guild.me.top_role.position - 1):
|
||||
if role < guild.me.top_role:
|
||||
await msgobj.edit(content=msgobj.content + 'moving role to higher position... ')
|
||||
await msgobj.edit(content=msgobj.content + "moving role to higher position... ")
|
||||
await role.edit(position=guild.me.top_role.position - 1)
|
||||
else:
|
||||
await msgobj.edit(content=msgobj.content + 'role is too high to manage.'
|
||||
' Please move it to below my highest role.')
|
||||
await msgobj.edit(
|
||||
content=msgobj.content + "role is too high to manage." " Please move it to below my highest role."
|
||||
)
|
||||
return
|
||||
|
||||
await msgobj.edit(content=msgobj.content + '(re)configuring channels... ')
|
||||
await msgobj.edit(content=msgobj.content + "(re)configuring channels... ")
|
||||
|
||||
for channel in guild.channels:
|
||||
await self.setup_channel(channel, role)
|
||||
|
||||
await msgobj.edit(content=msgobj.content + 'done.')
|
||||
await msgobj.edit(content=msgobj.content + "done.")
|
||||
|
||||
if role and role.id != role_id:
|
||||
await self.config.guild(guild).ROLE_ID.set(role.id)
|
||||
|
||||
@punishset.command(name='channel')
|
||||
@punishset.command(name="channel")
|
||||
async def punishset_channel(self, ctx, channel: discord.TextChannel = None):
|
||||
"""
|
||||
Sets or shows the punishment "timeout" channel.
|
||||
|
@ -613,13 +621,16 @@ class Punish(commands.Cog):
|
|||
await ctx.send("The timeout channel is currently %s." % current.mention)
|
||||
else:
|
||||
if current == channel:
|
||||
await ctx.send("The timeout channel is already %s. If you need to repair its permissions, use `%spunishset setup`." % (current.mention, ctx.prefix))
|
||||
await ctx.send(
|
||||
"The timeout channel is already %s. If you need to repair its permissions, use `%spunishset setup`."
|
||||
% (current.mention, ctx.prefix)
|
||||
)
|
||||
return
|
||||
|
||||
await self.config.guild(guild).CHANNEL_ID.set(channel.id)
|
||||
|
||||
role = await self.get_role(guild, create=True)
|
||||
update_msg = '{} to the %s role' % role
|
||||
update_msg = "{} to the %s role" % role
|
||||
grants = []
|
||||
denies = []
|
||||
perms = permissions_for_roles(channel, role)
|
||||
|
@ -631,7 +642,7 @@ class Punish(commands.Cog):
|
|||
|
||||
if getattr(perms, perm) != value:
|
||||
setattr(overwrite, perm, value)
|
||||
name = perm.replace('_', ' ').title().replace("Tts", "TTS")
|
||||
name = perm.replace("_", " ").title().replace("Tts", "TTS")
|
||||
|
||||
if value:
|
||||
grants.append(name)
|
||||
|
@ -640,8 +651,8 @@ class Punish(commands.Cog):
|
|||
|
||||
# Any changes made? Apply them.
|
||||
if grants or denies:
|
||||
grants = grants and ('grant ' + format_list(*grants))
|
||||
denies = denies and ('deny ' + format_list(*denies))
|
||||
grants = grants and ("grant " + format_list(*grants))
|
||||
denies = denies and ("deny " + format_list(*denies))
|
||||
to_join = [x for x in (grants, denies) if x]
|
||||
update_msg = update_msg.format(format_list(*to_join))
|
||||
|
||||
|
@ -655,14 +666,14 @@ class Punish(commands.Cog):
|
|||
await self.setup_channel(current, role)
|
||||
|
||||
if channel.permissions_for(guild.me).manage_roles:
|
||||
await ctx.send(info('Updating permissions in %s to %s...' % (channel.mention, update_msg)))
|
||||
await ctx.send(info("Updating permissions in %s to %s..." % (channel.mention, update_msg)))
|
||||
await channel.set_permissions(role, overwrite=overwrite)
|
||||
else:
|
||||
await ctx.send(error("I don't have permissions to %s." % update_msg))
|
||||
|
||||
await ctx.send("Timeout channel set to %s." % channel.mention)
|
||||
|
||||
@punishset.command(name='clear-channel')
|
||||
@punishset.command(name="clear-channel")
|
||||
async def punishset_clear_channel(self, ctx):
|
||||
"""
|
||||
Clears the timeout channel and resets its permissions
|
||||
|
@ -678,7 +689,7 @@ class Punish(commands.Cog):
|
|||
if current.permissions_for(guild.me).manage_roles:
|
||||
role = await self.get_role(guild, quiet=True)
|
||||
await self.setup_channel(current, role)
|
||||
msg = ' and its permissions reset'
|
||||
msg = " and its permissions reset"
|
||||
else:
|
||||
msg = ", but I don't have permissions to reset its permissions."
|
||||
|
||||
|
@ -686,7 +697,7 @@ class Punish(commands.Cog):
|
|||
else:
|
||||
await ctx.send("No timeout channel has been set yet.")
|
||||
|
||||
@punishset.command(name='case-min')
|
||||
@punishset.command(name="case-min")
|
||||
async def punishset_case_min(self, ctx, *, timespec: str = None):
|
||||
"""
|
||||
Set/disable or display the minimum punishment case duration
|
||||
|
@ -699,11 +710,11 @@ class Punish(commands.Cog):
|
|||
|
||||
if not timespec:
|
||||
if current:
|
||||
await ctx.send('Punishments longer than %s will create cases.' % generate_timespec(current))
|
||||
await ctx.send("Punishments longer than %s will create cases." % generate_timespec(current))
|
||||
else:
|
||||
await ctx.send("Punishment case creation is disabled.")
|
||||
else:
|
||||
if timespec.strip('\'"').lower() == 'disable':
|
||||
if timespec.strip("'\"").lower() == "disable":
|
||||
value = None
|
||||
else:
|
||||
try:
|
||||
|
@ -714,9 +725,9 @@ class Punish(commands.Cog):
|
|||
|
||||
await self.config.guild(guild).CASE_MIN_LENGTH.set(value)
|
||||
|
||||
await ctx.send('Punishments longer than %s will create cases.' % generate_timespec(value))
|
||||
await ctx.send("Punishments longer than %s will create cases." % generate_timespec(value))
|
||||
|
||||
@punishset.command(name='overrides')
|
||||
@punishset.command(name="overrides")
|
||||
async def punishset_overrides(self, ctx, *, channel_id: int = None):
|
||||
"""
|
||||
Copy or display the punish role overrides
|
||||
|
@ -751,52 +762,58 @@ class Punish(commands.Cog):
|
|||
confirm_msg = "Are you sure you want to copy overrides from this channel?"
|
||||
|
||||
if channel.type is discord.ChannelType.text:
|
||||
key = 'text'
|
||||
key = "text"
|
||||
elif channel.type is discord.ChannelType.voice:
|
||||
key = 'voice'
|
||||
key = "voice"
|
||||
else:
|
||||
await ctx.send(error("Unknown channel type!"))
|
||||
return
|
||||
|
||||
if confirm_msg:
|
||||
await ctx.send(warning(confirm_msg + '(reply `yes` within 30s to confirm)'))
|
||||
await ctx.send(warning(confirm_msg + "(reply `yes` within 30s to confirm)"))
|
||||
|
||||
def check(m):
|
||||
return m.author == ctx.author and m.channel == ctx.channel
|
||||
|
||||
try:
|
||||
reply = await self.bot.wait_for('message', check=check, timeout=30.0)
|
||||
if reply.content.strip(' `"\'').lower() != 'yes':
|
||||
await ctx.send('Commmand cancelled.')
|
||||
reply = await self.bot.wait_for("message", check=check, timeout=30.0)
|
||||
if reply.content.strip(" `\"'").lower() != "yes":
|
||||
await ctx.send("Commmand cancelled.")
|
||||
return
|
||||
except asyncio.TimeoutError:
|
||||
await ctx.send('Timed out waiting for a response.')
|
||||
await ctx.send("Timed out waiting for a response.")
|
||||
return
|
||||
|
||||
if key == 'text':
|
||||
if key == "text":
|
||||
await self.config.guild(guild).TEXT_OVERWRITE.set(overwrite_to_dict(overwrite))
|
||||
else:
|
||||
await self.config.guild(guild).VOICE_OVERWRITE.set(overwrite_to_dict(overwrite))
|
||||
|
||||
await ctx.send("{} channel overrides set to:\n".format(key.title()) +
|
||||
format_permissions(overwrite) +
|
||||
"\n\nRun `%spunishset setup` to apply them to all channels." % ctx.prefix)
|
||||
await ctx.send(
|
||||
"{} channel overrides set to:\n".format(key.title())
|
||||
+ format_permissions(overwrite)
|
||||
+ "\n\nRun `%spunishset setup` to apply them to all channels." % ctx.prefix
|
||||
)
|
||||
else:
|
||||
msg = []
|
||||
for key in ('text', 'voice'):
|
||||
if key == 'text':
|
||||
for key in ("text", "voice"):
|
||||
if key == "text":
|
||||
data = await self.config.guild(guild).TEXT_OVERWRITE()
|
||||
else:
|
||||
data = await self.config.guild(guild).VOICE_OVERWRITE()
|
||||
title = '%s permission overrides:' % key.title()
|
||||
title = "%s permission overrides:" % key.title()
|
||||
|
||||
if data == overwrite_to_dict(DEFAULT_TEXT_OVERWRITE) or data == overwrite_to_dict(DEFAULT_VOICE_OVERWRITE):
|
||||
title = title[:-1] + ' (defaults):'
|
||||
if data == overwrite_to_dict(DEFAULT_TEXT_OVERWRITE) or data == overwrite_to_dict(
|
||||
DEFAULT_VOICE_OVERWRITE
|
||||
):
|
||||
title = title[:-1] + " (defaults):"
|
||||
|
||||
msg.append(bold(title) + '\n' + format_permissions(overwrite_from_dict(data)))
|
||||
msg.append(bold(title) + "\n" + format_permissions(overwrite_from_dict(data)))
|
||||
|
||||
await ctx.send('\n\n'.join(msg))
|
||||
await ctx.send("\n\n".join(msg))
|
||||
|
||||
@punishset.command(name='reset-overrides')
|
||||
async def punishset_reset_overrides(self, ctx, channel_type: str = 'both'):
|
||||
@punishset.command(name="reset-overrides")
|
||||
async def punishset_reset_overrides(self, ctx, channel_type: str = "both"):
|
||||
"""
|
||||
Resets the punish role overrides for text, voice or both (default)
|
||||
|
||||
|
@ -804,21 +821,21 @@ class Punish(commands.Cog):
|
|||
for newly created channels.
|
||||
"""
|
||||
|
||||
channel_type = channel_type.strip('`"\' ').lower()
|
||||
channel_type = channel_type.strip("`\"' ").lower()
|
||||
|
||||
msg = []
|
||||
for key in ('text', 'voice'):
|
||||
if channel_type not in ['both', key]:
|
||||
for key in ("text", "voice"):
|
||||
if channel_type not in ["both", key]:
|
||||
continue
|
||||
|
||||
title = '%s permission overrides reset to:' % key.title()
|
||||
title = "%s permission overrides reset to:" % key.title()
|
||||
|
||||
if key == 'text':
|
||||
if key == "text":
|
||||
await self.config.guild(guild).TEXT_OVERWRITE.set(overwrite_to_dict(DEFAULT_TEXT_OVERWRITE))
|
||||
msg.append(bold(title) + '\n' + format_permissions(overwrite_to_dict(DEFAULT_TEXT_OVERWRITE)))
|
||||
msg.append(bold(title) + "\n" + format_permissions(overwrite_to_dict(DEFAULT_TEXT_OVERWRITE)))
|
||||
else:
|
||||
await self.config.guild(guild).VOICE_OVERWRITE.set(overwrite_to_dict(DEFAULT_VOICE_OVERWRITE))
|
||||
msg.append(bold(title) + '\n' + format_permissions(overwrite_to_dict(DEFAULT_VOICE_OVERWRITE)))
|
||||
msg.append(bold(title) + "\n" + format_permissions(overwrite_to_dict(DEFAULT_VOICE_OVERWRITE)))
|
||||
|
||||
if not msg:
|
||||
await ctx.send("Invalid channel type. Use `text`, `voice`, or `both` (the default, if not specified)")
|
||||
|
@ -826,7 +843,7 @@ class Punish(commands.Cog):
|
|||
|
||||
msg.append("Run `%spunishset setup` to apply them to all channels." % ctx.prefix)
|
||||
|
||||
await ctx.send('\n\n'.join(msg))
|
||||
await ctx.send("\n\n".join(msg))
|
||||
|
||||
async def get_role(self, guild, quiet=False, create=False):
|
||||
role_id = await self.config.guild(guild).ROLE_ID()
|
||||
|
@ -848,19 +865,19 @@ class Punish(commands.Cog):
|
|||
if not quiet:
|
||||
msgobj = await ctx.send(msg)
|
||||
|
||||
log.debug('Creating punish role in %s' % guild.name)
|
||||
log.debug("Creating punish role in %s" % guild.name)
|
||||
perms = discord.Permissions.none()
|
||||
role = await guild.create_role(name=DEFAULT_ROLE_NAME, permissions=perms, reason="punish cog.")
|
||||
await role.edit(position=guild.me.top_role.position - 1)
|
||||
|
||||
if not quiet:
|
||||
await msgobj.edit(content=msgobj.content + '\nconfiguring channels... ')
|
||||
await msgobj.edit(content=msgobj.content + "\nconfiguring channels... ")
|
||||
|
||||
for channel in guild.channels:
|
||||
await self.setup_channel(channel, role)
|
||||
|
||||
if not quiet:
|
||||
await msgobj.edit(content=msgobj.content + '\ndone.')
|
||||
await msgobj.edit(content=msgobj.content + "\ndone.")
|
||||
|
||||
if role and role.id != role_id:
|
||||
await self.config.guild(guild).ROLE_ID.set(role.id)
|
||||
|
@ -906,23 +923,23 @@ class Punish(commands.Cog):
|
|||
|
||||
for member_id, data in punished.items():
|
||||
|
||||
until = data['until']
|
||||
until = data["until"]
|
||||
member = guild.get_member(member_id)
|
||||
|
||||
if until and (until - time.time()) < 0:
|
||||
if member:
|
||||
reason = 'Punishment removal overdue, maybe the bot was offline. '
|
||||
reason = "Punishment removal overdue, maybe the bot was offline. "
|
||||
|
||||
if data['reason']:
|
||||
reason += data['reason']
|
||||
if data["reason"]:
|
||||
reason += data["reason"]
|
||||
|
||||
await self._unpunish(member, reason=reason)
|
||||
else: # member disappeared
|
||||
del(punished[str(member_id)])
|
||||
del punished[str(member_id)]
|
||||
elif member:
|
||||
# re-check roles
|
||||
user_roles = set(member.roles)
|
||||
removed_roles = set(role_memo.filter(data.get('removed_roles', ()), skip_nulls=True))
|
||||
removed_roles = set(role_memo.filter(data.get("removed_roles", ()), skip_nulls=True))
|
||||
removed_roles = user_roles & {r for r in removed_roles if r < me.top_role}
|
||||
user_roles -= removed_roles
|
||||
|
||||
|
@ -954,7 +971,7 @@ class Punish(commands.Cog):
|
|||
except Exception:
|
||||
pass
|
||||
|
||||
log.debug('queue manager dying')
|
||||
log.debug("queue manager dying")
|
||||
|
||||
while not self.queue.empty():
|
||||
self.queue.get_nowait()
|
||||
|
@ -985,7 +1002,7 @@ class Punish(commands.Cog):
|
|||
|
||||
return removed is not None
|
||||
|
||||
async def put_queue_event(self, run_at : float, *args):
|
||||
async def put_queue_event(self, run_at: float, *args):
|
||||
diff = run_at - time.time()
|
||||
|
||||
if args in self.enqueued:
|
||||
|
@ -1038,7 +1055,7 @@ class Punish(commands.Cog):
|
|||
remove_role_set = set(resolve_role_list(guild, remove_role_set))
|
||||
punished = await self.config.guild(guild).PUNISHED()
|
||||
current = punished.get(str(member.id), {})
|
||||
reason = reason or current.get('reason') # don't clear if not given
|
||||
reason = reason or current.get("reason") # don't clear if not given
|
||||
hierarchy_allowed = ctx.author.top_role > member.top_role
|
||||
case_min_length = await self.config.guild(guild).CASE_MIN_LENGTH()
|
||||
nitro_role = await self.config.guild(guild).NITRO_ID()
|
||||
|
@ -1051,7 +1068,7 @@ class Punish(commands.Cog):
|
|||
await ctx.send("You can't punish the bot.")
|
||||
return
|
||||
|
||||
if duration and duration.lower() in ['forever', 'inf', 'infinite']:
|
||||
if duration and duration.lower() in ["forever", "inf", "infinite"]:
|
||||
duration = None
|
||||
else:
|
||||
if not duration:
|
||||
|
@ -1071,7 +1088,7 @@ class Punish(commands.Cog):
|
|||
if role is None:
|
||||
return
|
||||
elif role >= guild.me.top_role:
|
||||
await ctx.send('The %s role is too high for me to manage.' % role)
|
||||
await ctx.send("The %s role is too high for me to manage." % role)
|
||||
return
|
||||
|
||||
# Call time() after getting the role due to potential creation delay
|
||||
|
@ -1085,22 +1102,26 @@ class Punish(commands.Cog):
|
|||
|
||||
try:
|
||||
if current:
|
||||
case_number = current.get('caseno')
|
||||
case_number = current.get("caseno")
|
||||
try:
|
||||
case = await modlog.get_case(case_number, guild, self.bot)
|
||||
except: # shouldn't happen
|
||||
await ctx.send(warning("Error, modlog case not found, but user is punished with case.\nTry unpunishing and punishing again."))
|
||||
except: # shouldn't happen
|
||||
await ctx.send(
|
||||
warning(
|
||||
"Error, modlog case not found, but user is punished with case.\nTry unpunishing and punishing again."
|
||||
)
|
||||
)
|
||||
return
|
||||
|
||||
moderator = ctx.author
|
||||
|
||||
try:
|
||||
edits = {'reason': reason}
|
||||
edits = {"reason": reason}
|
||||
|
||||
if moderator.id != current.get('by'):
|
||||
edits['amended_by'] = moderator
|
||||
if moderator.id != current.get("by"):
|
||||
edits["amended_by"] = moderator
|
||||
|
||||
edits['modified_at'] = ctx.message.created_at.timestamp()
|
||||
edits["modified_at"] = ctx.message.created_at.timestamp()
|
||||
|
||||
await case.edit(edits)
|
||||
except Exception as e:
|
||||
|
@ -1110,7 +1131,16 @@ class Punish(commands.Cog):
|
|||
updating_case = True
|
||||
|
||||
else:
|
||||
case = await modlog.create_case(self.bot, guild, now_date, "Timed Mute", member, moderator=ctx.author, reason=reason, until=mod_until)
|
||||
case = await modlog.create_case(
|
||||
self.bot,
|
||||
guild,
|
||||
now_date,
|
||||
"Timed Mute",
|
||||
member,
|
||||
moderator=ctx.author,
|
||||
reason=reason,
|
||||
until=mod_until,
|
||||
)
|
||||
case_number = case.case_number
|
||||
|
||||
except Exception as e:
|
||||
|
@ -1118,18 +1148,18 @@ class Punish(commands.Cog):
|
|||
else:
|
||||
case_number = None
|
||||
|
||||
subject = 'the %s role' % role.name
|
||||
subject = "the %s role" % role.name
|
||||
|
||||
if str(member.id) in punished:
|
||||
if role in member.roles:
|
||||
msg = '{0} already had the {1.name} role; resetting their timer.'
|
||||
msg = "{0} already had the {1.name} role; resetting their timer."
|
||||
else:
|
||||
msg = '{0} is missing the {1.name} role for some reason. I added it and reset their timer.'
|
||||
msg = "{0} is missing the {1.name} role for some reason. I added it and reset their timer."
|
||||
elif role in member.roles:
|
||||
msg = '{0} already had the {1.name} role, but had no timer; setting it now.'
|
||||
msg = "{0} already had the {1.name} role, but had no timer; setting it now."
|
||||
else:
|
||||
msg = 'Applied the {1.name} role to {0}.'
|
||||
subject = 'it'
|
||||
msg = "Applied the {1.name} role to {0}."
|
||||
subject = "it"
|
||||
|
||||
msg = msg.format(member, role)
|
||||
|
||||
|
@ -1137,24 +1167,24 @@ class Punish(commands.Cog):
|
|||
timespec = generate_timespec(duration)
|
||||
|
||||
if using_default:
|
||||
timespec += ' (the default)'
|
||||
timespec += " (the default)"
|
||||
|
||||
msg += ' I will remove %s in %s.' % (subject, timespec)
|
||||
msg += " I will remove %s in %s." % (subject, timespec)
|
||||
|
||||
if case_error:
|
||||
if isinstance(case_error, CaseMessageNotFound):
|
||||
case_error = 'the case message could not be found'
|
||||
case_error = "the case message could not be found"
|
||||
elif isinstance(case_error, NoModLogAccess):
|
||||
case_error = 'I do not have access to the modlog channel'
|
||||
case_error = "I do not have access to the modlog channel"
|
||||
else:
|
||||
case_error = None
|
||||
|
||||
if case_error:
|
||||
verb = 'updating' if updating_case else 'creating'
|
||||
msg += '\n\n' + warning('There was an error %s the modlog case: %s.' % (verb, case_error))
|
||||
verb = "updating" if updating_case else "creating"
|
||||
msg += "\n\n" + warning("There was an error %s the modlog case: %s." % (verb, case_error))
|
||||
elif case_number:
|
||||
verb = 'updated' if updating_case else 'created'
|
||||
msg += ' I also %s case #%i in the modlog.' % (verb, case_number)
|
||||
verb = "updated" if updating_case else "created"
|
||||
msg += " I also %s case #%i in the modlog." % (verb, case_number)
|
||||
|
||||
voice_overwrite = await self.config.guild(guild).VOICE_OVERWRITE()
|
||||
|
||||
|
@ -1175,12 +1205,12 @@ class Punish(commands.Cog):
|
|||
# build lists of roles that *should* be removed and ones that *can* be
|
||||
removed_roles = user_roles & remove_role_set
|
||||
too_high_to_remove = {r for r in removed_roles if r >= guild.me.top_role}
|
||||
user_roles -= (removed_roles - too_high_to_remove)
|
||||
user_roles -= removed_roles - too_high_to_remove
|
||||
user_roles.add(role) # add punish role to the set
|
||||
await member.edit(roles=user_roles, reason=f"punish {member}")
|
||||
|
||||
else:
|
||||
removed_roles = set(resolve_role_list(guild, current.get('removed_roles', [])))
|
||||
removed_roles = set(resolve_role_list(guild, current.get("removed_roles", [])))
|
||||
too_high_to_remove = {r for r in removed_roles if r >= guild.me.top_role}
|
||||
|
||||
if removed_roles:
|
||||
|
@ -1190,8 +1220,10 @@ class Punish(commands.Cog):
|
|||
|
||||
if too_high_to_remove:
|
||||
fmt_list = format_list(*(r.name for r in removed_roles))
|
||||
msg += "\n" + warning("These roles were too high to remove (fix hierarchy, then run "
|
||||
"`{}punishset sync-roles`): {}".format(ctx.prefix, fmt_list))
|
||||
msg += "\n" + warning(
|
||||
"These roles were too high to remove (fix hierarchy, then run "
|
||||
"`{}punishset sync-roles`): {}".format(ctx.prefix, fmt_list)
|
||||
)
|
||||
if member.voice:
|
||||
muted = member.voice.mute
|
||||
else:
|
||||
|
@ -1199,13 +1231,13 @@ class Punish(commands.Cog):
|
|||
|
||||
async with self.config.guild(guild).PUNISHED() as punished:
|
||||
punished[str(member.id)] = {
|
||||
'start' : current.get('start') or now, # don't override start time if updating
|
||||
'until' : until,
|
||||
'by' : current.get('by') or ctx.author.id, # don't override original moderator
|
||||
'reason' : reason,
|
||||
'unmute' : overwrite_denies_speak and not muted,
|
||||
'caseno' : case_number,
|
||||
'removed_roles' : [r.id for r in removed_roles]
|
||||
"start": current.get("start") or now, # don't override start time if updating
|
||||
"until": until,
|
||||
"by": current.get("by") or ctx.author.id, # don't override original moderator
|
||||
"reason": reason,
|
||||
"unmute": overwrite_denies_speak and not muted,
|
||||
"caseno": case_number,
|
||||
"removed_roles": [r.id for r in removed_roles],
|
||||
}
|
||||
|
||||
if member.voice and overwrite_denies_speak:
|
||||
|
@ -1256,8 +1288,8 @@ class Punish(commands.Cog):
|
|||
if role:
|
||||
data = await self.config.guild(guild).PUNISHED()
|
||||
member_data = data.get(str(member.id), {})
|
||||
caseno = member_data.get('caseno')
|
||||
removed_roles = set(resolve_role_list(guild, member_data.get('removed_roles', [])))
|
||||
caseno = member_data.get("caseno")
|
||||
removed_roles = set(resolve_role_list(guild, member_data.get("removed_roles", [])))
|
||||
|
||||
# Has to be done first to prevent triggering listeners
|
||||
await self._unpunish_data(member)
|
||||
|
@ -1280,20 +1312,20 @@ class Punish(commands.Cog):
|
|||
await member.edit(roles=user_roles, reason="punish end")
|
||||
|
||||
if update and caseno:
|
||||
until = member_data.get('until') or False
|
||||
until = member_data.get("until") or False
|
||||
# fallback gracefully
|
||||
moderator = moderator or guild.get_member(member_data.get('by')) or guild.me
|
||||
moderator = moderator or guild.get_member(member_data.get("by")) or guild.me
|
||||
|
||||
if until:
|
||||
until = datetime.utcfromtimestamp(until).timestamp()
|
||||
|
||||
edits = {'reason': reason}
|
||||
edits = {"reason": reason}
|
||||
|
||||
if moderator.id != data.get('by'):
|
||||
edits['amended_by'] = moderator
|
||||
if moderator.id != data.get("by"):
|
||||
edits["amended_by"] = moderator
|
||||
|
||||
edits['modified_at'] = time.time()
|
||||
edits['until'] = until
|
||||
edits["modified_at"] = time.time()
|
||||
edits["until"] = until
|
||||
|
||||
try:
|
||||
case = await modlog.get_case(caseno, guild, self.bot)
|
||||
|
@ -1301,7 +1333,7 @@ class Punish(commands.Cog):
|
|||
except Exception:
|
||||
pass
|
||||
|
||||
if member_data.get('unmute', False):
|
||||
if member_data.get("unmute", False):
|
||||
if member.voice:
|
||||
if member.voice.channel:
|
||||
await member.edit(mute=False)
|
||||
|
@ -1313,7 +1345,7 @@ class Punish(commands.Cog):
|
|||
if quiet:
|
||||
return True
|
||||
|
||||
msg = 'Your punishment in %s has ended.' % member.guild.name
|
||||
msg = "Your punishment in %s has ended." % member.guild.name
|
||||
|
||||
if reason:
|
||||
msg += "\nReason: %s" % reason
|
||||
|
@ -1323,8 +1355,9 @@ class Punish(commands.Cog):
|
|||
|
||||
if too_high_to_restore:
|
||||
fmt_list = format_list(*(r.name for r in too_high_to_restore))
|
||||
msg += "\n" + warning("These roles were too high for me to restore: {}. "
|
||||
"Ask a mod for help.".format(fmt_list))
|
||||
msg += "\n" + warning(
|
||||
"These roles were too high for me to restore: {}. " "Ask a mod for help.".format(fmt_list)
|
||||
)
|
||||
|
||||
try:
|
||||
await member.send(msg)
|
||||
|
@ -1338,7 +1371,7 @@ class Punish(commands.Cog):
|
|||
|
||||
async with self.config.guild(guild).PUNISHED() as punished:
|
||||
if str(member.id) in punished:
|
||||
del(punished[str(member.id)])
|
||||
del punished[str(member.id)]
|
||||
|
||||
# Listeners
|
||||
@commands.Cog.listener()
|
||||
|
@ -1365,14 +1398,14 @@ class Punish(commands.Cog):
|
|||
new_roles = {role.id: role for role in after.roles}
|
||||
|
||||
if role in before.roles and role.id not in new_roles:
|
||||
msg = 'Punishment manually ended early by a moderator/admin.'
|
||||
msg = "Punishment manually ended early by a moderator/admin."
|
||||
|
||||
if member_data['reason']:
|
||||
msg += '\nReason was: ' + member_data['reason']
|
||||
if member_data["reason"]:
|
||||
msg += "\nReason was: " + member_data["reason"]
|
||||
|
||||
await self._unpunish(after, reason=msg, update=True)
|
||||
else:
|
||||
to_remove = {new_roles.get(role_id) for role_id in member_data.get('removed_roles', [])}
|
||||
to_remove = {new_roles.get(role_id) for role_id in member_data.get("removed_roles", [])}
|
||||
to_remove = [r for r in to_remove if r and r < after.guild.me.top_role]
|
||||
|
||||
if to_remove:
|
||||
|
@ -1393,7 +1426,7 @@ class Punish(commands.Cog):
|
|||
member = self.bot.get_guild(guild.id).get_member(member.id)
|
||||
role = await self.get_role(member.guild, quiet=True)
|
||||
|
||||
until = data['until']
|
||||
until = data["until"]
|
||||
duration = until - time.time()
|
||||
|
||||
if role and duration > 0:
|
||||
|
@ -1433,7 +1466,7 @@ class Punish(commands.Cog):
|
|||
|
||||
msg = "Punishment ended early due to ban."
|
||||
|
||||
if member_data.get('reason'):
|
||||
msg += '\n\nOriginal reason was: ' + member_data['reason']
|
||||
if member_data.get("reason"):
|
||||
msg += "\n\nOriginal reason was: " + member_data["reason"]
|
||||
|
||||
await self._unpunish(member, reason=msg, apply_roles=False, update=True, quiet=True)
|
||||
|
|
|
@ -2,13 +2,14 @@ import re
|
|||
import discord
|
||||
|
||||
UNIT_TABLE = (
|
||||
(('weeks', 'wks', 'w'), 60 * 60 * 24 * 7),
|
||||
(('days', 'dys', 'd'), 60 * 60 * 24),
|
||||
(('hours', 'hrs', 'h'), 60 * 60),
|
||||
(('minutes', 'mins', 'm'), 60),
|
||||
(('seconds', 'secs', 's'), 1),
|
||||
(("weeks", "wks", "w"), 60 * 60 * 24 * 7),
|
||||
(("days", "dys", "d"), 60 * 60 * 24),
|
||||
(("hours", "hrs", "h"), 60 * 60),
|
||||
(("minutes", "mins", "m"), 60),
|
||||
(("seconds", "secs", "s"), 1),
|
||||
)
|
||||
|
||||
|
||||
class BadTimeExpr(Exception):
|
||||
pass
|
||||
|
||||
|
@ -23,24 +24,23 @@ def _find_unit(unit):
|
|||
def parse_time(time):
|
||||
time = time.lower()
|
||||
if not time.isdigit():
|
||||
time = re.split(r'\s*([\d.]+\s*[^\d\s,;]*)(?:[,;\s]|and)*', time)
|
||||
time = re.split(r"\s*([\d.]+\s*[^\d\s,;]*)(?:[,;\s]|and)*", time)
|
||||
time = sum(map(_timespec_sec, filter(None, time)))
|
||||
return int(time)
|
||||
|
||||
|
||||
def _timespec_sec(expr):
|
||||
atoms = re.split(r'([\d.]+)\s*([^\d\s]*)', expr)
|
||||
atoms = re.split(r"([\d.]+)\s*([^\d\s]*)", expr)
|
||||
atoms = list(filter(None, atoms))
|
||||
|
||||
if len(atoms) > 2: # This shouldn't ever happen
|
||||
raise BadTimeExpr("invalid expression: '%s'" % expr)
|
||||
elif len(atoms) == 2:
|
||||
names, length = _find_unit(atoms[1])
|
||||
if atoms[0].count('.') > 1 or \
|
||||
not atoms[0].replace('.', '').isdigit():
|
||||
if atoms[0].count(".") > 1 or not atoms[0].replace(".", "").isdigit():
|
||||
raise BadTimeExpr("Not a number: '%s'" % atoms[0])
|
||||
else:
|
||||
names, length = _find_unit('seconds')
|
||||
names, length = _find_unit("seconds")
|
||||
|
||||
try:
|
||||
return float(atoms[0]) * length
|
||||
|
@ -59,48 +59,46 @@ def generate_timespec(sec: int, short=False, micro=False) -> str:
|
|||
|
||||
if n:
|
||||
if micro:
|
||||
s = '%d%s' % (n, names[2])
|
||||
s = "%d%s" % (n, names[2])
|
||||
elif short:
|
||||
s = '%d%s' % (n, names[1])
|
||||
s = "%d%s" % (n, names[1])
|
||||
else:
|
||||
s = '%d %s' % (n, names[0])
|
||||
s = "%d %s" % (n, names[0])
|
||||
|
||||
if n <= 1 and not (micro and names[2] == 's'):
|
||||
s = s.rstrip('s')
|
||||
if n <= 1 and not (micro and names[2] == "s"):
|
||||
s = s.rstrip("s")
|
||||
|
||||
timespec.append(s)
|
||||
|
||||
if len(timespec) > 1:
|
||||
if micro:
|
||||
spec = ''.join(timespec)
|
||||
spec = "".join(timespec)
|
||||
|
||||
segments = timespec[:-1], timespec[-1:]
|
||||
spec = ' and '.join(', '.join(x) for x in segments)
|
||||
spec = " and ".join(", ".join(x) for x in segments)
|
||||
elif timespec:
|
||||
spec = timespec[0]
|
||||
else:
|
||||
return '0'
|
||||
return "0"
|
||||
|
||||
if neg:
|
||||
spec += ' ago'
|
||||
spec += " ago"
|
||||
|
||||
return spec
|
||||
|
||||
|
||||
def format_list(*items, join='and', delim=', '):
|
||||
def format_list(*items, join="and", delim=", "):
|
||||
if len(items) > 1:
|
||||
return (' %s ' % join).join((delim.join(items[:-1]), items[-1]))
|
||||
return (" %s " % join).join((delim.join(items[:-1]), items[-1]))
|
||||
elif items:
|
||||
return items[0]
|
||||
else:
|
||||
return ''
|
||||
return ""
|
||||
|
||||
|
||||
def overwrite_to_dict(overwrite):
|
||||
allow, deny = overwrite.pair()
|
||||
return {
|
||||
'allow' : allow.value,
|
||||
'deny' : deny.value
|
||||
}
|
||||
return {"allow": allow.value, "deny": deny.value}
|
||||
|
||||
|
||||
def format_permissions(permissions, include_null=False):
|
||||
|
@ -116,10 +114,10 @@ def format_permissions(permissions, include_null=False):
|
|||
else:
|
||||
continue
|
||||
|
||||
entries.append(symbol + ' ' + perm.replace('_', ' ').title().replace("Tts", "TTS"))
|
||||
entries.append(symbol + " " + perm.replace("_", " ").title().replace("Tts", "TTS"))
|
||||
|
||||
if entries:
|
||||
return '\n'.join(entries)
|
||||
return "\n".join(entries)
|
||||
else:
|
||||
return "No permission entries."
|
||||
|
||||
|
@ -130,7 +128,7 @@ def getmname(mid, guild):
|
|||
if member:
|
||||
return str(member)
|
||||
else:
|
||||
return '(absent user #%s)' % mid
|
||||
return "(absent user #%s)" % mid
|
||||
|
||||
|
||||
def role_from_string(guild, rolename, roles=None):
|
||||
|
@ -186,7 +184,7 @@ def permissions_for_roles(channel, *roles):
|
|||
if overwrite.id == default.id:
|
||||
base.handle_overwrite(allow=overwrite.allow, deny=overwrite.deny)
|
||||
|
||||
if overwrite.type == 'role' and overwrite.id in role_ids:
|
||||
if overwrite.type == "role" and overwrite.id in role_ids:
|
||||
denies |= overwrite.deny
|
||||
allows |= overwrite.allow
|
||||
|
||||
|
@ -218,6 +216,6 @@ def permissions_for_roles(channel, *roles):
|
|||
|
||||
|
||||
def overwrite_from_dict(data):
|
||||
allow = discord.Permissions(data.get('allow', 0))
|
||||
deny = discord.Permissions(data.get('deny', 0))
|
||||
allow = discord.Permissions(data.get("allow", 0))
|
||||
deny = discord.Permissions(data.get("deny", 0))
|
||||
return discord.PermissionOverwrite.from_pair(allow, deny)
|
||||
|
|
|
@ -14,6 +14,7 @@ import asyncio
|
|||
import os
|
||||
import json
|
||||
|
||||
|
||||
class RolePlay(commands.Cog):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
@ -31,7 +32,8 @@ class RolePlay(commands.Cog):
|
|||
"lotsa spaghetti",
|
||||
"a brick",
|
||||
"a slice of cheese",
|
||||
"my foot"],
|
||||
"my foot",
|
||||
],
|
||||
"high_iq_msgs": [
|
||||
"wow!",
|
||||
"that's pretty big.",
|
||||
|
@ -40,7 +42,8 @@ class RolePlay(commands.Cog):
|
|||
"someone here is actually smart.",
|
||||
"thats a dab.",
|
||||
"<:aureliawink:549481308519399425>",
|
||||
"you must of watched Rick and Morty."],
|
||||
"you must of watched Rick and Morty.",
|
||||
],
|
||||
"low_iq_msgs": [
|
||||
":rofl:",
|
||||
"oof.",
|
||||
|
@ -49,7 +52,8 @@ class RolePlay(commands.Cog):
|
|||
"awww you're special aren't you.",
|
||||
":crying_cat_face:",
|
||||
"god I'm sorry (not).",
|
||||
"I didn't know people could have IQ that low."]
|
||||
"I didn't know people could have IQ that low.",
|
||||
],
|
||||
}
|
||||
|
||||
self.config.register_guild(**self.default_guild)
|
||||
|
@ -104,12 +108,11 @@ class RolePlay(commands.Cog):
|
|||
elif user.id == botid:
|
||||
user = ctx.message.author
|
||||
botname = ctx.bot.user.name
|
||||
await ctx.send("`-" + botname + " slaps " + user.display_name +
|
||||
" multiple times with " +
|
||||
(choice(slap_items) + "-`"))
|
||||
await ctx.send(
|
||||
"`-" + botname + " slaps " + user.display_name + " multiple times with " + (choice(slap_items) + "-`")
|
||||
)
|
||||
else:
|
||||
await ctx.send("`-slaps " + user.display_name + " with " +
|
||||
(choice(slap_items) + "-`"))
|
||||
await ctx.send("`-slaps " + user.display_name + " with " + (choice(slap_items) + "-`"))
|
||||
|
||||
@slap.command(name="add")
|
||||
@checks.admin()
|
||||
|
@ -126,7 +129,7 @@ class RolePlay(commands.Cog):
|
|||
|
||||
@slap.command(name="remove")
|
||||
@checks.admin()
|
||||
async def _remove_slap(self, ctx, slap_item: str=""):
|
||||
async def _remove_slap(self, ctx, slap_item: str = ""):
|
||||
"""Removes item to use for slaps!"""
|
||||
guild = ctx.guild
|
||||
slap_items = await self.config.guild(guild).slap_items()
|
||||
|
@ -146,7 +149,7 @@ class RolePlay(commands.Cog):
|
|||
msg = ""
|
||||
for item in slap_items:
|
||||
msg += "+ {}\n".format(item)
|
||||
pages = pagify(msg) # pages is an iterator of pages
|
||||
pages = pagify(msg) # pages is an iterator of pages
|
||||
|
||||
for page in pages:
|
||||
await ctx.send(box(page, lang="diff"))
|
||||
|
@ -173,9 +176,8 @@ class RolePlay(commands.Cog):
|
|||
except json.decoder.JSONDecodeError:
|
||||
await ctx.send("Invalid or malformed json file.")
|
||||
|
||||
|
||||
@commands.group(invoke_without_command=True)
|
||||
async def iq(self, ctx, *users : discord.Member):
|
||||
async def iq(self, ctx, *users: discord.Member):
|
||||
"""
|
||||
Gets IQ of a user. Use multiple users to compare IQs
|
||||
"""
|
||||
|
@ -199,7 +201,9 @@ class RolePlay(commands.Cog):
|
|||
iqs = sorted(iqs.items(), key=lambda x: x[1])
|
||||
|
||||
for user, iq in iqs:
|
||||
msg += "{}'s iq is {}, {}\n".format(user.display_name, iq, choice(high_iq_msgs) if int(iq) > 130 else choice(low_iq_messages))
|
||||
msg += "{}'s iq is {}, {}\n".format(
|
||||
user.display_name, iq, choice(high_iq_msgs) if int(iq) > 130 else choice(low_iq_messages)
|
||||
)
|
||||
|
||||
await ctx.send(msg)
|
||||
|
||||
|
@ -215,11 +219,11 @@ class RolePlay(commands.Cog):
|
|||
|
||||
for high_phrase in high_iq_msgs:
|
||||
msg1 += "+ {}\n".format(high_phrase)
|
||||
high_pages = pagify(msg1) # pages is an iterator of pages
|
||||
high_pages = pagify(msg1) # pages is an iterator of pages
|
||||
|
||||
for low_phrase in low_iq_msgs:
|
||||
msg2 += "+ {}\n".format(low_phrase)
|
||||
low_pages = pagify(msg2) # pages is an iterator of pages
|
||||
low_pages = pagify(msg2) # pages is an iterator of pages
|
||||
|
||||
for high_page in high_pages:
|
||||
await ctx.send(box(high_page, lang="diff"))
|
||||
|
@ -255,7 +259,7 @@ class RolePlay(commands.Cog):
|
|||
|
||||
@iq.command(name="removehigh")
|
||||
@checks.admin()
|
||||
async def _removehigh_iq(self, ctx, high_phrase: str=""):
|
||||
async def _removehigh_iq(self, ctx, high_phrase: str = ""):
|
||||
"""Removes phrases for high IQ's!"""
|
||||
guild = ctx.guild
|
||||
high_iq_msgs = await self.config.guild(guild).high_iq_msgs()
|
||||
|
@ -274,7 +278,7 @@ class RolePlay(commands.Cog):
|
|||
|
||||
@iq.command(name="removelow")
|
||||
@checks.admin()
|
||||
async def _removelow_iq(self, ctx, low_phrase: str=""):
|
||||
async def _removelow_iq(self, ctx, low_phrase: str = ""):
|
||||
"""Removes phrases for low IQ's!"""
|
||||
guild = ctx.guild
|
||||
low_iq_msgs = await self.config.guild(guild).low_iq_msgs()
|
||||
|
@ -306,7 +310,7 @@ class RolePlay(commands.Cog):
|
|||
largest_factor = 1
|
||||
else:
|
||||
largest_factor = [x for x in range(1, horses) if horses % x == 0][-1]
|
||||
#largest_factor = [x for x in largest_factor if x <= 15][-1]
|
||||
# largest_factor = [x for x in largest_factor if x <= 15][-1]
|
||||
if largest_factor == 1:
|
||||
largest_factor = horses
|
||||
rows = 1
|
||||
|
@ -367,7 +371,7 @@ class RolePlay(commands.Cog):
|
|||
if user.id == ctx.bot.user.id:
|
||||
await ctx.send(":newspaper2: :newspaper2: :newspaper2: " + italics(ctx.message.author.display_name))
|
||||
else:
|
||||
await ctx.send(":newspaper2: " + italics(user.display_name) )
|
||||
await ctx.send(":newspaper2: " + italics(user.display_name))
|
||||
|
||||
@commands.command()
|
||||
async def flip(self, ctx, *, user: discord.Member = None):
|
||||
|
|
Loading…
Reference in a new issue