ryuko-ng/cogs/mod.py

566 lines
21 KiB
Python
Raw Normal View History

2018-12-23 15:07:59 +00:00
import discord
from discord.ext import commands
from discord.ext.commands import Cog
2018-12-23 15:07:59 +00:00
import config
2019-02-20 11:21:50 +00:00
from helpers.checks import check_if_staff, check_if_bot_manager
from helpers.userlogs import userlog
from helpers.restrictions import add_restriction, remove_restriction
2019-02-20 11:21:50 +00:00
import io
2018-12-23 15:07:59 +00:00
class Mod(Cog):
2018-12-23 15:07:59 +00:00
def __init__(self, bot):
self.bot = bot
def check_if_target_is_staff(self, target):
return any(r.id in config.staff_role_ids for r in target.roles)
2019-02-20 11:21:50 +00:00
@commands.guild_only()
@commands.check(check_if_bot_manager)
@commands.command()
async def setguildicon(self, ctx, url):
"""Changes guild icon, bot manager only."""
2019-02-20 11:32:19 +00:00
img_bytes = await self.bot.aiogetbytes(url)
await ctx.guild.edit(icon=img_bytes, reason=str(ctx.author))
2019-02-20 11:21:50 +00:00
await ctx.send(f"Done!")
log_channel = self.bot.get_channel(config.modlog_channel)
2020-05-29 15:09:47 +00:00
log_msg = (
f"✏️ **Guild Icon Update**: {ctx.author} changed the guild icon."
2020-05-29 15:10:52 +00:00
f"\n🔗 __Jump__: <{ctx.message.jump_url}>"
2020-05-29 15:09:47 +00:00
)
img_filename = url.split("/")[-1].split("#")[0] # hacky
img_file = discord.File(io.BytesIO(img_bytes), filename=img_filename)
2019-02-20 11:32:19 +00:00
await log_channel.send(log_msg, file=img_file)
2019-02-20 11:21:50 +00:00
2018-12-23 20:50:05 +00:00
@commands.guild_only()
@commands.check(check_if_staff)
@commands.command()
async def mute(self, ctx, target: discord.Member, *, reason: str = ""):
"""Mutes a user, staff only."""
2018-12-24 08:40:36 +00:00
# Hedge-proofing the code
if target == ctx.author:
2018-12-24 08:41:28 +00:00
return await ctx.send("You can't do mod actions on yourself.")
elif target == self.bot.user:
return await ctx.send(
2020-05-17 20:40:23 +00:00
f"I'm sorry {ctx.author.mention}, I'm afraid I can't do that."
)
2018-12-24 08:40:36 +00:00
elif self.check_if_target_is_staff(target):
return await ctx.send(
2020-05-17 20:40:23 +00:00
"I can't mute this user as they're a member of staff."
)
2018-12-23 20:50:05 +00:00
userlog(target.id, ctx.author, reason, "mutes", target.name)
2019-01-07 08:49:19 +00:00
safe_name = await commands.clean_content().convert(ctx, str(target))
2018-12-23 20:50:05 +00:00
dm_message = f"You were muted!"
if reason:
dm_message += f' The given reason is: "{reason}".'
2018-12-23 20:50:05 +00:00
try:
await target.send(dm_message)
except discord.errors.Forbidden:
# Prevents kick issues in cases where user blocked bot
# or has DMs disabled
pass
mute_role = ctx.guild.get_role(config.mute_role)
await target.add_roles(mute_role, reason=str(ctx.author))
chan_message = (
f"🔇 **Muted**: {ctx.author.mention} muted "
f"{target.mention} | {safe_name}\n"
f"🏷 __User ID__: {target.id}\n"
)
2018-12-23 20:50:05 +00:00
if reason:
chan_message += f'✏️ __Reason__: "{reason}"'
2018-12-23 20:50:05 +00:00
else:
chan_message += (
"Please add an explanation below. In the future, "
"it is recommended to use `.mute <user> [reason]`"
" as the reason is automatically sent to the user."
)
2018-12-23 20:50:05 +00:00
2020-05-29 15:10:52 +00:00
chan_message += f"\n🔗 __Jump__: <{ctx.message.jump_url}>"
2019-02-04 22:54:40 +00:00
log_channel = self.bot.get_channel(config.modlog_channel)
2018-12-23 20:50:05 +00:00
await log_channel.send(chan_message)
await ctx.send(f"{target.mention} can no longer speak.")
add_restriction(target.id, config.mute_role)
2018-12-23 20:50:05 +00:00
@commands.guild_only()
@commands.check(check_if_staff)
@commands.command()
async def unmute(self, ctx, target: discord.Member):
"""Unmutes a user, staff only."""
2019-01-07 08:49:19 +00:00
safe_name = await commands.clean_content().convert(ctx, str(target))
2018-12-23 20:50:05 +00:00
mute_role = ctx.guild.get_role(config.mute_role)
await target.remove_roles(mute_role, reason=str(ctx.author))
chan_message = (
f"🔈 **Unmuted**: {ctx.author.mention} unmuted "
f"{target.mention} | {safe_name}\n"
f"🏷 __User ID__: {target.id}\n"
)
2018-12-23 20:50:05 +00:00
2020-05-29 15:10:52 +00:00
chan_message += f"\n🔗 __Jump__: <{ctx.message.jump_url}>"
2019-02-04 22:54:40 +00:00
log_channel = self.bot.get_channel(config.modlog_channel)
2018-12-23 20:50:05 +00:00
await log_channel.send(chan_message)
await ctx.send(f"{target.mention} can now speak again.")
remove_restriction(target.id, config.mute_role)
2018-12-23 20:50:05 +00:00
@commands.guild_only()
@commands.bot_has_permissions(kick_members=True)
@commands.check(check_if_staff)
@commands.command()
async def kick(self, ctx, target: discord.Member, *, reason: str = ""):
"""Kicks a user, staff only."""
2018-12-24 08:40:36 +00:00
# Hedge-proofing the code
if target == ctx.author:
2018-12-24 08:41:28 +00:00
return await ctx.send("You can't do mod actions on yourself.")
elif target == self.bot.user:
return await ctx.send(
2020-05-17 20:40:23 +00:00
f"I'm sorry {ctx.author.mention}, I'm afraid I can't do that."
)
2018-12-24 08:40:36 +00:00
elif self.check_if_target_is_staff(target):
return await ctx.send(
2020-05-17 20:40:23 +00:00
"I can't kick this user as they're a member of staff."
)
userlog(target.id, ctx.author, reason, "kicks", target.name)
2019-01-07 08:49:19 +00:00
safe_name = await commands.clean_content().convert(ctx, str(target))
dm_message = f"You were kicked from {ctx.guild.name}."
if reason:
dm_message += f' The given reason is: "{reason}".'
dm_message += (
"\n\nYou are able to rejoin the server,"
" but please be sure to behave when participating again."
)
try:
await target.send(dm_message)
except discord.errors.Forbidden:
# Prevents kick issues in cases where user blocked bot
# or has DMs disabled
pass
await target.kick(reason=f"{ctx.author}, reason: {reason}")
chan_message = (
f"👢 **Kick**: {ctx.author.mention} kicked "
f"{target.mention} | {safe_name}\n"
f"🏷 __User ID__: {target.id}\n"
)
if reason:
chan_message += f'✏️ __Reason__: "{reason}"'
else:
chan_message += (
"Please add an explanation below. In the future"
", it is recommended to use "
"`.kick <user> [reason]`"
" as the reason is automatically sent to the user."
)
2020-05-29 15:10:52 +00:00
chan_message += f"\n🔗 __Jump__: <{ctx.message.jump_url}>"
2019-02-04 22:54:40 +00:00
log_channel = self.bot.get_channel(config.modlog_channel)
2018-12-23 19:03:40 +00:00
await log_channel.send(chan_message)
2019-10-30 20:04:59 +00:00
await ctx.send(f"👢 {safe_name}, 👍.")
@commands.guild_only()
@commands.bot_has_permissions(ban_members=True)
@commands.check(check_if_staff)
@commands.command(aliases=["yeet"])
async def ban(self, ctx, target: discord.Member, *, reason: str = ""):
"""Bans a user, staff only."""
2018-12-24 08:40:36 +00:00
# Hedge-proofing the code
if target == ctx.author:
if target.id == 181627658520625152:
return await ctx.send(
"https://cdn.discordapp.com/attachments/286612533757083648/403080855402315796/rehedge.PNG"
)
2019-09-17 10:23:21 +00:00
return await ctx.send("hedgeberg#7337 is now b&. 👍")
elif target == self.bot.user:
return await ctx.send(
2020-05-17 20:40:23 +00:00
f"I'm sorry {ctx.author.mention}, I'm afraid I can't do that."
)
2018-12-24 08:40:36 +00:00
elif self.check_if_target_is_staff(target):
2020-05-17 20:40:23 +00:00
return await ctx.send("I can't ban this user as they're a member of staff.")
userlog(target.id, ctx.author, reason, "bans", target.name)
2019-01-07 08:49:19 +00:00
safe_name = await commands.clean_content().convert(ctx, str(target))
dm_message = f"You were banned from {ctx.guild.name}."
if reason:
dm_message += f' The given reason is: "{reason}".'
dm_message += "\n\nThis ban does not expire."
try:
await target.send(dm_message)
except discord.errors.Forbidden:
2018-12-23 22:11:01 +00:00
# Prevents ban issues in cases where user blocked bot
# or has DMs disabled
pass
await target.ban(
reason=f"{ctx.author}, reason: {reason}", delete_message_days=0
)
chan_message = (
f"⛔ **Ban**: {ctx.author.mention} banned "
f"{target.mention} | {safe_name}\n"
f"🏷 __User ID__: {target.id}\n"
)
if reason:
chan_message += f'✏️ __Reason__: "{reason}"'
else:
chan_message += (
"Please add an explanation below. In the future"
", it is recommended to use `.ban <user> [reason]`"
" as the reason is automatically sent to the user."
)
2020-05-29 15:10:52 +00:00
chan_message += f"\n🔗 __Jump__: <{ctx.message.jump_url}>"
2019-02-04 22:54:40 +00:00
log_channel = self.bot.get_channel(config.modlog_channel)
2018-12-25 11:13:02 +00:00
await log_channel.send(chan_message)
await ctx.send(f"{safe_name} is now b&. 👍")
2018-12-23 23:25:30 +00:00
@commands.guild_only()
@commands.bot_has_permissions(ban_members=True)
@commands.check(check_if_staff)
2019-01-13 13:33:35 +00:00
@commands.command(aliases=["softban"])
2018-12-23 23:25:30 +00:00
async def hackban(self, ctx, target: int, *, reason: str = ""):
"""Bans a user with their ID, doesn't message them, staff only."""
2019-07-01 20:14:51 +00:00
target_user = await self.bot.fetch_user(target)
2018-12-25 11:33:49 +00:00
target_member = ctx.guild.get_member(target)
2018-12-24 08:40:36 +00:00
# Hedge-proofing the code
2018-12-25 11:33:49 +00:00
if target == ctx.author.id:
2018-12-24 08:41:28 +00:00
return await ctx.send("You can't do mod actions on yourself.")
elif target == self.bot.user:
return await ctx.send(
2020-05-17 20:40:23 +00:00
f"I'm sorry {ctx.author.mention}, I'm afraid I can't do that."
)
2018-12-25 11:33:49 +00:00
elif target_member and self.check_if_target_is_staff(target_member):
2020-05-17 20:40:23 +00:00
return await ctx.send("I can't ban this user as they're a member of staff.")
2018-12-23 23:25:30 +00:00
userlog(target, ctx.author, reason, "bans", target_user.name)
2019-01-07 08:49:19 +00:00
safe_name = await commands.clean_content().convert(ctx, str(target))
2018-12-23 23:25:30 +00:00
await ctx.guild.ban(
target_user, reason=f"{ctx.author}, reason: {reason}", delete_message_days=0
)
chan_message = (
f"⛔ **Hackban**: {ctx.author.mention} banned "
f"{target_user.mention} | {safe_name}\n"
f"🏷 __User ID__: {target}\n"
)
2018-12-23 23:25:30 +00:00
if reason:
chan_message += f'✏️ __Reason__: "{reason}"'
2018-12-23 23:25:30 +00:00
else:
chan_message += (
"Please add an explanation below. In the future"
", it is recommended to use "
"`.hackban <user> [reason]`."
)
2018-12-23 23:25:30 +00:00
2020-05-29 15:10:52 +00:00
chan_message += f"\n🔗 __Jump__: <{ctx.message.jump_url}>"
2019-02-04 22:54:40 +00:00
log_channel = self.bot.get_channel(config.modlog_channel)
2018-12-23 19:03:40 +00:00
await log_channel.send(chan_message)
await ctx.send(f"{safe_name} is now b&. 👍")
2020-05-17 20:40:23 +00:00
@commands.guild_only()
@commands.bot_has_permissions(ban_members=True)
@commands.check(check_if_staff)
@commands.command()
async def unban(self, ctx, target: int, *, reason: str = ""):
"""Unbans a user with their ID, doesn't message them, staff only."""
target_user = await self.bot.fetch_user(target)
safe_name = await commands.clean_content().convert(ctx, str(target))
await ctx.guild.unban(target_user, reason=f"{ctx.author}, reason: {reason}")
chan_message = (
f"⚠️ **Unban**: {ctx.author.mention} unbanned "
f"{target_user.mention} | {safe_name}\n"
f"🏷 __User ID__: {target}\n"
)
if reason:
chan_message += f'✏️ __Reason__: "{reason}"'
else:
chan_message += (
"Please add an explanation below. In the future"
", it is recommended to use "
"`.unban <user id> [reason]`."
)
2020-05-29 15:10:52 +00:00
chan_message += f"\n🔗 __Jump__: <{ctx.message.jump_url}>"
2020-05-17 20:40:23 +00:00
log_channel = self.bot.get_channel(config.modlog_channel)
await log_channel.send(chan_message)
await ctx.send(f"{safe_name} is now unb&.")
@commands.guild_only()
2018-12-23 15:44:16 +00:00
@commands.bot_has_permissions(ban_members=True)
@commands.check(check_if_staff)
@commands.command()
async def silentban(self, ctx, target: discord.Member, *, reason: str = ""):
"""Bans a user, staff only."""
2018-12-24 08:40:36 +00:00
# Hedge-proofing the code
if target == ctx.author:
2018-12-24 08:41:28 +00:00
return await ctx.send("You can't do mod actions on yourself.")
elif target == self.bot.user:
return await ctx.send(
2020-05-17 20:40:23 +00:00
f"I'm sorry {ctx.author.mention}, I'm afraid I can't do that."
)
2018-12-24 08:40:36 +00:00
elif self.check_if_target_is_staff(target):
2020-05-17 20:40:23 +00:00
return await ctx.send("I can't ban this user as they're a member of staff.")
2018-12-23 15:44:16 +00:00
userlog(target.id, ctx.author, reason, "bans", target.name)
2019-01-07 08:49:19 +00:00
safe_name = await commands.clean_content().convert(ctx, str(target))
2018-12-23 15:44:16 +00:00
await target.ban(
reason=f"{ctx.author}, reason: {reason}", delete_message_days=0
)
chan_message = (
f"⛔ **Silent ban**: {ctx.author.mention} banned "
f"{target.mention} | {safe_name}\n"
f"🏷 __User ID__: {target.id}\n"
)
2018-12-23 15:44:16 +00:00
if reason:
chan_message += f'✏️ __Reason__: "{reason}"'
2018-12-23 15:44:16 +00:00
else:
chan_message += (
"Please add an explanation below. In the future"
", it is recommended to use `.ban <user> [reason]`"
" as the reason is automatically sent to the user."
)
2018-12-23 15:44:16 +00:00
2020-05-29 15:10:52 +00:00
chan_message += f"\n🔗 __Jump__: <{ctx.message.jump_url}>"
2019-02-04 22:54:40 +00:00
log_channel = self.bot.get_channel(config.modlog_channel)
2018-12-23 19:03:40 +00:00
await log_channel.send(chan_message)
2018-12-23 15:44:16 +00:00
2018-12-23 19:32:48 +00:00
@commands.guild_only()
@commands.check(check_if_staff)
@commands.command()
async def approve(self, ctx, target: discord.Member, role: str = "community"):
2018-12-26 08:18:11 +00:00
"""Add a role to a user (default: community), staff only."""
if role not in config.named_roles:
return await ctx.send(
"No such role! Available roles: " + ",".join(config.named_roles)
)
2019-02-04 22:54:40 +00:00
log_channel = self.bot.get_channel(config.modlog_channel)
target_role = ctx.guild.get_role(config.named_roles[role])
if target_role in target.roles:
return await ctx.send("Target already has this role.")
await target.add_roles(target_role, reason=str(ctx.author))
2018-12-23 20:01:43 +00:00
await ctx.send(f"Approved {target.mention} to `{role}` role.")
2018-12-23 19:32:48 +00:00
await log_channel.send(
2020-05-29 15:09:47 +00:00
f"✅ Approved: {ctx.author.mention} added"
f" {role} to {target.mention}"
2020-05-29 15:10:52 +00:00
f"\n🔗 __Jump__: <{ctx.message.jump_url}>"
)
2018-12-23 19:32:48 +00:00
@commands.guild_only()
@commands.check(check_if_staff)
@commands.command(aliases=["unapprove"])
async def revoke(self, ctx, target: discord.Member, role: str = "community"):
2018-12-26 08:18:11 +00:00
"""Remove a role from a user (default: community), staff only."""
if role not in config.named_roles:
return await ctx.send(
"No such role! Available roles: " + ",".join(config.named_roles)
)
2019-02-04 22:54:40 +00:00
log_channel = self.bot.get_channel(config.modlog_channel)
target_role = ctx.guild.get_role(config.named_roles[role])
if target_role not in target.roles:
return await ctx.send("Target doesn't have this role.")
await target.remove_roles(target_role, reason=str(ctx.author))
2018-12-23 20:01:43 +00:00
await ctx.send(f"Un-approved {target.mention} from `{role}` role.")
2018-12-23 19:32:48 +00:00
await log_channel.send(
f"❌ Un-approved: {ctx.author.mention} removed"
f" {role} from {target.mention}"
2020-05-29 15:10:52 +00:00
f"\n🔗 __Jump__: <{ctx.message.jump_url}>"
)
2018-12-23 19:32:48 +00:00
2018-12-23 20:59:08 +00:00
@commands.guild_only()
@commands.check(check_if_staff)
@commands.command(aliases=["clear"])
async def purge(self, ctx, limit: int, channel: discord.TextChannel = None):
2018-12-26 08:18:11 +00:00
"""Clears a given number of messages, staff only."""
2019-02-04 22:54:40 +00:00
log_channel = self.bot.get_channel(config.modlog_channel)
2018-12-23 20:59:08 +00:00
if not channel:
channel = ctx.channel
await channel.purge(limit=limit)
msg = (
f"🗑 **Purged**: {ctx.author.mention} purged {limit} "
f"messages in {channel.mention}."
)
2018-12-23 20:59:08 +00:00
await log_channel.send(msg)
2018-12-23 22:11:01 +00:00
@commands.guild_only()
@commands.check(check_if_staff)
@commands.command()
async def warn(self, ctx, target: discord.Member, *, reason: str = ""):
2018-12-26 08:18:11 +00:00
"""Warns a user, staff only."""
2018-12-24 08:40:36 +00:00
# Hedge-proofing the code
if target == ctx.author:
2018-12-24 08:41:28 +00:00
return await ctx.send("You can't do mod actions on yourself.")
elif target == self.bot.user:
return await ctx.send(
2020-05-17 20:40:23 +00:00
f"I'm sorry {ctx.author.mention}, I'm afraid I can't do that."
)
2018-12-24 08:40:36 +00:00
elif self.check_if_target_is_staff(target):
return await ctx.send(
2020-05-17 20:40:23 +00:00
"I can't warn this user as they're a member of staff."
)
2018-12-23 22:11:01 +00:00
2019-02-04 22:54:40 +00:00
log_channel = self.bot.get_channel(config.modlog_channel)
warn_count = userlog(target.id, ctx.author, reason, "warns", target.name)
2018-12-23 22:11:01 +00:00
2019-02-25 09:10:06 +00:00
safe_name = await commands.clean_content().convert(ctx, str(target))
chan_msg = (
f"⚠️ **Warned**: {ctx.author.mention} warned "
f"{target.mention} (warn #{warn_count}) "
f"| {safe_name}\n"
)
2019-02-25 09:10:06 +00:00
2018-12-23 22:11:01 +00:00
msg = f"You were warned on {ctx.guild.name}."
if reason:
msg += " The given reason is: " + reason
msg += (
f"\n\nPlease read the rules in {config.rules_url}. "
f"This is warn #{warn_count}."
)
2018-12-23 22:11:01 +00:00
if warn_count == 2:
msg += " __The next warn will automatically kick.__"
if warn_count == 3:
msg += (
"\n\nYou were kicked because of this warning. "
"You can join again right away. "
"Two more warnings will result in an automatic ban."
)
2018-12-23 22:11:01 +00:00
if warn_count == 4:
msg += (
"\n\nYou were kicked because of this warning. "
"This is your final warning. "
"You can join again, but "
"**one more warn will result in a ban**."
)
2019-02-25 09:10:06 +00:00
chan_msg += "**This resulted in an auto-kick.**\n"
2018-12-23 22:11:01 +00:00
if warn_count == 5:
msg += "\n\nYou were automatically banned due to five warnings."
2019-02-25 09:10:06 +00:00
chan_msg += "**This resulted in an auto-ban.**\n"
2018-12-23 22:11:01 +00:00
try:
await target.send(msg)
except discord.errors.Forbidden:
# Prevents log issues in cases where user blocked bot
# or has DMs disabled
pass
if warn_count == 3 or warn_count == 4:
await target.kick()
if warn_count >= 5: # just in case
await target.ban(reason="exceeded warn limit", delete_message_days=0)
await ctx.send(
f"{target.mention} warned. " f"User has {warn_count} warning(s)."
)
2019-01-07 08:49:19 +00:00
2018-12-23 22:11:01 +00:00
if reason:
chan_msg += f'✏️ __Reason__: "{reason}"'
2018-12-23 22:11:01 +00:00
else:
chan_msg += (
"Please add an explanation below. In the future"
", it is recommended to use `.warn <user> [reason]`"
" as the reason is automatically sent to the user."
)
2020-05-29 15:10:52 +00:00
chan_msg += f"\n🔗 __Jump__: <{ctx.message.jump_url}>"
2019-02-25 09:10:06 +00:00
await log_channel.send(chan_msg)
2018-12-23 22:11:01 +00:00
2018-12-23 22:36:36 +00:00
@commands.guild_only()
@commands.check(check_if_staff)
@commands.command(aliases=["setnick", "nick"])
async def nickname(self, ctx, target: discord.Member, *, nick: str = ""):
"""Sets a user's nickname, staff only.
2018-12-23 22:36:36 +00:00
Just send .nickname <user> to wipe the nickname."""
2018-12-26 08:18:11 +00:00
try:
if nick:
await target.edit(nick=nick, reason=str(ctx.author))
else:
await target.edit(nick=None, reason=str(ctx.author))
await ctx.send("Successfully set nickname.")
except discord.errors.Forbidden:
await ctx.send(
"I don't have the permission to set that user's nickname.\n"
"User's top role may be above mine, or I may lack Manage Nicknames permission."
)
2018-12-23 22:36:36 +00:00
2018-12-23 23:25:30 +00:00
@commands.guild_only()
@commands.check(check_if_staff)
@commands.command(aliases=["echo"])
async def say(self, ctx, *, the_text: str):
"""Repeats a given text, staff only."""
await ctx.send(the_text)
2018-12-23 23:25:30 +00:00
@commands.guild_only()
@commands.check(check_if_staff)
@commands.command()
async def speak(self, ctx, channel: discord.TextChannel, *, the_text: str):
"""Repeats a given text in a given channel, staff only."""
await channel.send(the_text)
@commands.guild_only()
@commands.check(check_if_staff)
@commands.command(aliases=["setplaying", "setgame"])
async def playing(self, ctx, *, game: str = ""):
"""Sets the bot's currently played game name, staff only.
Just send .playing to wipe the playing state."""
if game:
await self.bot.change_presence(activity=discord.Game(name=game))
else:
await self.bot.change_presence(activity=None)
await ctx.send("Successfully set game.")
2018-12-26 09:45:00 +00:00
@commands.guild_only()
@commands.check(check_if_staff)
@commands.command(aliases=["setbotnick", "botnick", "robotnick"])
async def botnickname(self, ctx, *, nick: str = ""):
"""Sets the bot's nickname, staff only.
2018-12-26 09:45:00 +00:00
Just send .botnickname to wipe the nickname."""
if nick:
await ctx.guild.me.edit(nick=nick, reason=str(ctx.author))
2018-12-26 09:45:00 +00:00
else:
await ctx.guild.me.edit(nick=None, reason=str(ctx.author))
await ctx.send("Successfully set bot nickname.")
2018-12-23 15:07:59 +00:00
def setup(bot):
2018-12-26 08:18:11 +00:00
bot.add_cog(Mod(bot))