mirror of
https://github.com/Ryujinx/ryuko-ng.git
synced 2024-12-23 07:15:34 +00:00
Massive cleanup of code, many new features
- added logging and listing of kick/ban/mute events - add usernotes (.note to add a note to a user, .notes to fetch them) - split off mod.py into many files, cleanup on many features - renamed .listwarns to .userlog - renamed .mywarns to .myuserlog
This commit is contained in:
parent
2b50f56fe7
commit
6a8819a2a8
|
@ -72,10 +72,10 @@ Main goal of this project is to get Robocop functionality done, secondary goal i
|
||||||
- [ ] New feature: Highlights (problematic words automatically get posted to modmail channel)
|
- [ ] New feature: Highlights (problematic words automatically get posted to modmail channel)
|
||||||
- [ ] New feature: Modmail
|
- [ ] New feature: Modmail
|
||||||
- [ ] New feature: Submiterr
|
- [ ] New feature: Submiterr
|
||||||
- [ ] New moderation feature: Display of mutes on listwarns
|
|
||||||
- [ ] New moderation feature: User notes
|
|
||||||
- [ ] New moderation feature: mutetime (mute with time)
|
- [ ] New moderation feature: mutetime (mute with time)
|
||||||
- [ ] New moderation feature: timelock (channel lockdown with time)
|
- [ ] New moderation feature: timelock (channel lockdown with time)
|
||||||
|
- [x] New moderation feature: Display of mutes, bans and kicks on listwarns (.userlog now)
|
||||||
|
- [x] New moderation feature: User notes
|
||||||
- [x] New moderation feature: Reaction removing features (thanks misson20000!)
|
- [x] New moderation feature: Reaction removing features (thanks misson20000!)
|
||||||
- [x] New moderation feature: User nickname change
|
- [x] New moderation feature: User nickname change
|
||||||
- [x] New self-moderation feature: .mywarns
|
- [x] New self-moderation feature: .mywarns
|
||||||
|
|
|
@ -47,6 +47,9 @@ initial_extensions = ['cogs.common',
|
||||||
'cogs.legacy',
|
'cogs.legacy',
|
||||||
'cogs.links',
|
'cogs.links',
|
||||||
'cogs.mod',
|
'cogs.mod',
|
||||||
|
'cogs.mod_note',
|
||||||
|
'cogs.mod_reacts',
|
||||||
|
'cogs.mod_userlog',
|
||||||
'cogs.meme']
|
'cogs.meme']
|
||||||
|
|
||||||
bot = commands.Bot(command_prefix=get_prefix,
|
bot = commands.Bot(command_prefix=get_prefix,
|
||||||
|
|
430
cogs/mod.py
430
cogs/mod.py
|
@ -1,10 +1,9 @@
|
||||||
import asyncio
|
|
||||||
import discord
|
import discord
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
import config
|
import config
|
||||||
import json
|
|
||||||
import time
|
|
||||||
from helpers.checks import check_if_staff
|
from helpers.checks import check_if_staff
|
||||||
|
from helpers.userlogs import userlog
|
||||||
|
from helpers.restrictions import add_restriction, remove_restriction
|
||||||
|
|
||||||
|
|
||||||
class Mod:
|
class Mod:
|
||||||
|
@ -14,30 +13,7 @@ class Mod:
|
||||||
def check_if_target_is_staff(self, target):
|
def check_if_target_is_staff(self, target):
|
||||||
return any(r.id in config.staff_role_ids for r in target.roles)
|
return any(r.id in config.staff_role_ids for r in target.roles)
|
||||||
|
|
||||||
async def add_restriction(self, member, rst):
|
|
||||||
# from kurisu source, credits go to ihaveamac
|
|
||||||
with open("data/restrictions.json", "r") as f:
|
|
||||||
rsts = json.load(f)
|
|
||||||
if str(member.id) not in rsts:
|
|
||||||
rsts[str(member.id)] = []
|
|
||||||
if rst not in rsts[str(member.id)]:
|
|
||||||
rsts[str(member.id)].append(rst)
|
|
||||||
with open("data/restrictions.json", "w") as f:
|
|
||||||
json.dump(rsts, f)
|
|
||||||
|
|
||||||
async def remove_restriction(self, member, rst):
|
|
||||||
# from kurisu source, credits go to ihaveamac
|
|
||||||
with open("data/restrictions.json", "r") as f:
|
|
||||||
rsts = json.load(f)
|
|
||||||
if str(member.id) not in rsts:
|
|
||||||
rsts[str(member.id)] = []
|
|
||||||
if rst in rsts[str(member.id)]:
|
|
||||||
rsts[str(member.id)].remove(rst)
|
|
||||||
with open("data/restrictions.json", "w") as f:
|
|
||||||
json.dump(rsts, f)
|
|
||||||
|
|
||||||
@commands.guild_only()
|
@commands.guild_only()
|
||||||
@commands.bot_has_permissions(kick_members=True)
|
|
||||||
@commands.check(check_if_staff)
|
@commands.check(check_if_staff)
|
||||||
@commands.command()
|
@commands.command()
|
||||||
async def mute(self, ctx, target: discord.Member, *, reason: str = ""):
|
async def mute(self, ctx, target: discord.Member, *, reason: str = ""):
|
||||||
|
@ -49,6 +25,8 @@ class Mod:
|
||||||
return await ctx.send("I can't mute this user as "
|
return await ctx.send("I can't mute this user as "
|
||||||
"they're a member of staff.")
|
"they're a member of staff.")
|
||||||
|
|
||||||
|
userlog(target.id, ctx.author, reason, "mutes", target.name)
|
||||||
|
|
||||||
safe_name = self.bot.escape_message(str(target))
|
safe_name = self.bot.escape_message(str(target))
|
||||||
|
|
||||||
dm_message = f"You were muted!"
|
dm_message = f"You were muted!"
|
||||||
|
@ -79,10 +57,9 @@ class Mod:
|
||||||
log_channel = self.bot.get_channel(config.log_channel)
|
log_channel = self.bot.get_channel(config.log_channel)
|
||||||
await log_channel.send(chan_message)
|
await log_channel.send(chan_message)
|
||||||
await ctx.send(f"{target.mention} can no longer speak.")
|
await ctx.send(f"{target.mention} can no longer speak.")
|
||||||
await self.add_restriction(target, config.mute_role)
|
await add_restriction(target, config.mute_role)
|
||||||
|
|
||||||
@commands.guild_only()
|
@commands.guild_only()
|
||||||
@commands.bot_has_permissions(kick_members=True)
|
|
||||||
@commands.check(check_if_staff)
|
@commands.check(check_if_staff)
|
||||||
@commands.command()
|
@commands.command()
|
||||||
async def unmute(self, ctx, target: discord.Member):
|
async def unmute(self, ctx, target: discord.Member):
|
||||||
|
@ -99,7 +76,7 @@ class Mod:
|
||||||
log_channel = self.bot.get_channel(config.log_channel)
|
log_channel = self.bot.get_channel(config.log_channel)
|
||||||
await log_channel.send(chan_message)
|
await log_channel.send(chan_message)
|
||||||
await ctx.send(f"{target.mention} can now speak again.")
|
await ctx.send(f"{target.mention} can now speak again.")
|
||||||
await self.remove_restriction(target, config.mute_role)
|
await remove_restriction(target, config.mute_role)
|
||||||
|
|
||||||
@commands.guild_only()
|
@commands.guild_only()
|
||||||
@commands.bot_has_permissions(kick_members=True)
|
@commands.bot_has_permissions(kick_members=True)
|
||||||
|
@ -114,6 +91,8 @@ class Mod:
|
||||||
return await ctx.send("I can't kick this user as "
|
return await ctx.send("I can't kick this user as "
|
||||||
"they're a member of staff.")
|
"they're a member of staff.")
|
||||||
|
|
||||||
|
userlog(target.id, ctx.author, reason, "kicks", target.name)
|
||||||
|
|
||||||
safe_name = self.bot.escape_message(str(target))
|
safe_name = self.bot.escape_message(str(target))
|
||||||
|
|
||||||
dm_message = f"You were kicked from {ctx.guild.name}."
|
dm_message = f"You were kicked from {ctx.guild.name}."
|
||||||
|
@ -156,6 +135,8 @@ class Mod:
|
||||||
return await ctx.send("I can't ban this user as "
|
return await ctx.send("I can't ban this user as "
|
||||||
"they're a member of staff.")
|
"they're a member of staff.")
|
||||||
|
|
||||||
|
userlog(target.id, ctx.author, reason, "bans", target.name)
|
||||||
|
|
||||||
safe_name = self.bot.escape_message(str(target))
|
safe_name = self.bot.escape_message(str(target))
|
||||||
|
|
||||||
dm_message = f"You were banned from {ctx.guild.name}."
|
dm_message = f"You were banned from {ctx.guild.name}."
|
||||||
|
@ -201,6 +182,8 @@ class Mod:
|
||||||
return await ctx.send("I can't ban this user as "
|
return await ctx.send("I can't ban this user as "
|
||||||
"they're a member of staff.")
|
"they're a member of staff.")
|
||||||
|
|
||||||
|
userlog(target, ctx.author, reason, "bans", target_user.name)
|
||||||
|
|
||||||
safe_name = self.bot.escape_message(str(target_user))
|
safe_name = self.bot.escape_message(str(target_user))
|
||||||
|
|
||||||
await ctx.guild.ban(target_user,
|
await ctx.guild.ban(target_user,
|
||||||
|
@ -220,20 +203,6 @@ class Mod:
|
||||||
await log_channel.send(chan_message)
|
await log_channel.send(chan_message)
|
||||||
await ctx.send(f"{safe_name} is now b&. 👍")
|
await ctx.send(f"{safe_name} is now b&. 👍")
|
||||||
|
|
||||||
@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)
|
|
||||||
|
|
||||||
@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.guild_only()
|
||||||
@commands.bot_has_permissions(ban_members=True)
|
@commands.bot_has_permissions(ban_members=True)
|
||||||
@commands.check(check_if_staff)
|
@commands.check(check_if_staff)
|
||||||
|
@ -247,6 +216,8 @@ class Mod:
|
||||||
return await ctx.send("I can't ban this user as "
|
return await ctx.send("I can't ban this user as "
|
||||||
"they're a member of staff.")
|
"they're a member of staff.")
|
||||||
|
|
||||||
|
userlog(target.id, ctx.author, reason, "bans", target.name)
|
||||||
|
|
||||||
safe_name = self.bot.escape_message(str(target))
|
safe_name = self.bot.escape_message(str(target))
|
||||||
|
|
||||||
await target.ban(reason=f"{ctx.author}, reason: {reason}",
|
await target.ban(reason=f"{ctx.author}, reason: {reason}",
|
||||||
|
@ -264,25 +235,6 @@ class Mod:
|
||||||
log_channel = self.bot.get_channel(config.log_channel)
|
log_channel = self.bot.get_channel(config.log_channel)
|
||||||
await log_channel.send(chan_message)
|
await log_channel.send(chan_message)
|
||||||
|
|
||||||
@commands.guild_only()
|
|
||||||
@commands.check(check_if_staff)
|
|
||||||
@commands.command()
|
|
||||||
async def userinfo(self, ctx, *, user: discord.Member):
|
|
||||||
"""Gets user info, staff only."""
|
|
||||||
role = user.top_role.name
|
|
||||||
if role == "@everyone":
|
|
||||||
role = "@ everyone"
|
|
||||||
await ctx.send(f"user = {user}\n"
|
|
||||||
f"id = {user.id}\n"
|
|
||||||
f"avatar = {user.avatar_url}\n"
|
|
||||||
f"bot = {user.bot}\n"
|
|
||||||
f"created_at = {user.created_at}\n"
|
|
||||||
f"display_name = {user.display_name}\n"
|
|
||||||
f"joined_at = {user.joined_at}\n"
|
|
||||||
f"activities = `{user.activities}`\n"
|
|
||||||
f"color = {user.colour}\n"
|
|
||||||
f"top_role = {role}\n")
|
|
||||||
|
|
||||||
@commands.guild_only()
|
@commands.guild_only()
|
||||||
@commands.check(check_if_staff)
|
@commands.check(check_if_staff)
|
||||||
@commands.command()
|
@commands.command()
|
||||||
|
@ -329,50 +281,6 @@ class Mod:
|
||||||
await log_channel.send(f"❌ Un-approved: {ctx.author.mention} removed"
|
await log_channel.send(f"❌ Un-approved: {ctx.author.mention} removed"
|
||||||
f" {role} from {target.mention}")
|
f" {role} from {target.mention}")
|
||||||
|
|
||||||
@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.")
|
|
||||||
|
|
||||||
@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.
|
|
||||||
|
|
||||||
Just send .botnickname to wipe the nickname."""
|
|
||||||
|
|
||||||
if nick:
|
|
||||||
await ctx.guild.me.edit(nick=nick, reason=str(ctx.author))
|
|
||||||
else:
|
|
||||||
await ctx.guild.me.edit(nick=None, reason=str(ctx.author))
|
|
||||||
|
|
||||||
await ctx.send("Successfully set nickname.")
|
|
||||||
|
|
||||||
@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.
|
|
||||||
|
|
||||||
Just send .nickname <user> to wipe the nickname."""
|
|
||||||
|
|
||||||
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.")
|
|
||||||
|
|
||||||
@commands.guild_only()
|
@commands.guild_only()
|
||||||
@commands.check(check_if_staff)
|
@commands.check(check_if_staff)
|
||||||
@commands.command(aliases=["clear"])
|
@commands.command(aliases=["clear"])
|
||||||
|
@ -399,21 +307,8 @@ class Mod:
|
||||||
"they're a member of staff.")
|
"they're a member of staff.")
|
||||||
|
|
||||||
log_channel = self.bot.get_channel(config.log_channel)
|
log_channel = self.bot.get_channel(config.log_channel)
|
||||||
with open("data/warnsv2.json", "r") as f:
|
warn_count = userlog(target.id, ctx.author, reason,
|
||||||
warns = json.load(f)
|
"warns", target.name)
|
||||||
if str(target.id) not in warns:
|
|
||||||
warns[str(target.id)] = {"warns": []}
|
|
||||||
warns[str(target.id)]["name"] = str(target)
|
|
||||||
timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
|
|
||||||
warn_data = {"issuer_id": ctx.author.id,
|
|
||||||
"issuer_name": ctx.author.name,
|
|
||||||
"reason": reason,
|
|
||||||
"timestamp": timestamp}
|
|
||||||
warns[str(target.id)]["warns"].append(warn_data)
|
|
||||||
with open("data/warnsv2.json", "w") as f:
|
|
||||||
json.dump(warns, f)
|
|
||||||
|
|
||||||
warn_count = len(warns[str(target.id)]["warns"])
|
|
||||||
|
|
||||||
msg = f"You were warned on {ctx.guild.name}."
|
msg = f"You were warned on {ctx.guild.name}."
|
||||||
if reason:
|
if reason:
|
||||||
|
@ -457,254 +352,83 @@ class Mod:
|
||||||
" as the reason is automatically sent to the user."
|
" as the reason is automatically sent to the user."
|
||||||
await log_channel.send(msg)
|
await log_channel.send(msg)
|
||||||
|
|
||||||
def get_warns_embed_for_id(self, uid: str, name: str):
|
|
||||||
embed = discord.Embed(color=discord.Color.dark_red())
|
|
||||||
embed.set_author(name=f"Warns for {name}")
|
|
||||||
with open("data/warnsv2.json", "r") as f:
|
|
||||||
warns = json.load(f)
|
|
||||||
try:
|
|
||||||
if len(warns[uid]["warns"]):
|
|
||||||
for idx, warn in enumerate(warns[uid]["warns"]):
|
|
||||||
embed.add_field(name=f"{idx + 1}: {warn['timestamp']}",
|
|
||||||
value=f"Issuer: {warn['issuer_name']}\n"
|
|
||||||
f"Reason: {warn['reason']}")
|
|
||||||
else:
|
|
||||||
embed.description = "There are none!"
|
|
||||||
embed.color = discord.Color.green()
|
|
||||||
except KeyError: # if the user is not in the file
|
|
||||||
embed.description = "ID doesn't exist in saved "\
|
|
||||||
"warns (there likely aren't any warns)."
|
|
||||||
embed.color = discord.Color.green()
|
|
||||||
return embed
|
|
||||||
|
|
||||||
def clear_warns_from_id(self, uid: str):
|
|
||||||
with open("data/warnsv2.json", "r") as f:
|
|
||||||
warns = json.load(f)
|
|
||||||
if uid not in warns:
|
|
||||||
return f"<@{uid}> has no warns!"
|
|
||||||
warn_count = len(warns[uid]["warns"])
|
|
||||||
if not warn_count:
|
|
||||||
return f"<@{uid}> has no warns!"
|
|
||||||
warns[uid]["warns"] = []
|
|
||||||
with open("data/warnsv2.json", "w") as f:
|
|
||||||
json.dump(warns, f)
|
|
||||||
return f"<@{uid}> no longer has any warns!"
|
|
||||||
|
|
||||||
def delete_warns_from_id(self, uid: str, idx: int):
|
|
||||||
with open("data/warnsv2.json", "r") as f:
|
|
||||||
warns = json.load(f)
|
|
||||||
if uid not in warns:
|
|
||||||
return f"<@{uid}> has no warns!"
|
|
||||||
warn_count = len(warns[uid]["warns"])
|
|
||||||
if not warn_count:
|
|
||||||
return f"<@{uid}> has no warns!"
|
|
||||||
if idx > warn_count:
|
|
||||||
return "Warn index is higher than "\
|
|
||||||
f"warn count ({warn_count})!"
|
|
||||||
if idx < 1:
|
|
||||||
return "Warn index is below 1!"
|
|
||||||
warn = warns[uid]["warns"][idx - 1]
|
|
||||||
embed = discord.Embed(color=discord.Color.dark_red(),
|
|
||||||
title=f"Warn {idx} on {warn['timestamp']}",
|
|
||||||
description=f"Issuer: {warn['issuer_name']}\n"
|
|
||||||
f"Reason: {warn['reason']}")
|
|
||||||
del warns[uid]["warns"][idx - 1]
|
|
||||||
with open("data/warnsv2.json", "w") as f:
|
|
||||||
json.dump(warns, f)
|
|
||||||
return embed
|
|
||||||
|
|
||||||
@commands.guild_only()
|
@commands.guild_only()
|
||||||
@commands.check(check_if_staff)
|
@commands.check(check_if_staff)
|
||||||
@commands.command()
|
@commands.command(aliases=["setnick", "nick"])
|
||||||
async def listwarns(self, ctx, target: discord.Member):
|
async def nickname(self, ctx, target: discord.Member, *, nick: str = ""):
|
||||||
"""Lists warns for a user, staff only."""
|
"""Sets a user's nickname, staff only.
|
||||||
embed = self.get_warns_embed_for_id(str(target.id), str(target))
|
|
||||||
await ctx.send(embed=embed)
|
|
||||||
|
|
||||||
@commands.guild_only()
|
Just send .nickname <user> to wipe the nickname."""
|
||||||
@commands.command()
|
|
||||||
async def mywarns(self, ctx):
|
|
||||||
"""Lists your warns."""
|
|
||||||
embed = discord.Embed(color=discord.Color.dark_red())
|
|
||||||
uid = str(ctx.author.id)
|
|
||||||
embed.set_author(name=f"{ctx.author.name}'s warns")
|
|
||||||
with open("data/warnsv2.json", "r") as f:
|
|
||||||
warns = json.load(f)
|
|
||||||
try:
|
|
||||||
if len(warns[uid]["warns"]):
|
|
||||||
for idx, warn in enumerate(warns[uid]["warns"]):
|
|
||||||
embed.add_field(name=f"{idx + 1}: {warn['timestamp']}",
|
|
||||||
value=f"Reason: {warn['reason']}")
|
|
||||||
else:
|
|
||||||
embed.description = "There are none! Good for you."
|
|
||||||
embed.color = discord.Color.green()
|
|
||||||
except KeyError: # if the user is not in the file
|
|
||||||
embed.description = "ID doesn't exist in saved "\
|
|
||||||
"warns (there likely aren't any warns)."
|
|
||||||
embed.color = discord.Color.green()
|
|
||||||
await ctx.send(embed=embed)
|
|
||||||
|
|
||||||
@commands.guild_only()
|
if nick:
|
||||||
@commands.check(check_if_staff)
|
await target.edit(nick=nick, reason=str(ctx.author))
|
||||||
@commands.command()
|
|
||||||
async def listwarnsid(self, ctx, target: int):
|
|
||||||
"""Lists warns for a user by ID, staff only."""
|
|
||||||
embed = self.get_warns_embed_for_id(str(target), str(target))
|
|
||||||
await ctx.send(embed=embed)
|
|
||||||
|
|
||||||
@commands.guild_only()
|
|
||||||
@commands.check(check_if_staff)
|
|
||||||
@commands.command()
|
|
||||||
async def clearwarns(self, ctx, target: discord.Member):
|
|
||||||
"""Clears all warns for a user, staff only."""
|
|
||||||
log_channel = self.bot.get_channel(config.log_channel)
|
|
||||||
msg = self.clear_warns_from_id(str(target.id))
|
|
||||||
await ctx.send(msg)
|
|
||||||
msg = f"🗑 **Cleared warns**: {ctx.member.mention} cleared"\
|
|
||||||
f" warns of {target.mention} | "\
|
|
||||||
f"{self.bot.escape_message(target)}"
|
|
||||||
await log_channel.send(msg)
|
|
||||||
|
|
||||||
@commands.guild_only()
|
|
||||||
@commands.check(check_if_staff)
|
|
||||||
@commands.command()
|
|
||||||
async def clearwarnsid(self, ctx, target: int):
|
|
||||||
"""Clears all warns for a user from their userid, staff only."""
|
|
||||||
log_channel = self.bot.get_channel(config.log_channel)
|
|
||||||
msg = self.clear_warns_from_id(str(target))
|
|
||||||
await ctx.send(msg)
|
|
||||||
msg = f"🗑 **Cleared warns**: {ctx.member.mention} cleared"\
|
|
||||||
f" warns of <@{target}> "
|
|
||||||
await log_channel.send(msg)
|
|
||||||
|
|
||||||
@commands.guild_only()
|
|
||||||
@commands.check(check_if_staff)
|
|
||||||
@commands.command()
|
|
||||||
async def delwarn(self, ctx, target: discord.Member, idx: int):
|
|
||||||
"""Removes a specific warn from a user, staff only."""
|
|
||||||
log_channel = self.bot.get_channel(config.log_channel)
|
|
||||||
del_warn = self.delete_warns_from_id(str(target.id), idx)
|
|
||||||
# This is hell.
|
|
||||||
if isinstance(del_warn, discord.Embed):
|
|
||||||
await ctx.send(f"{target.mention} has a warning removed!")
|
|
||||||
msg = f"🗑 **Deleted warn**: {ctx.author.mention} removed "\
|
|
||||||
f"warn {idx} from {target.mention} | "\
|
|
||||||
f"{self.bot.escape_message(target)}"
|
|
||||||
await log_channel.send(msg, embed=del_warn)
|
|
||||||
else:
|
else:
|
||||||
await ctx.send(del_warn)
|
await target.edit(nick=None, reason=str(ctx.author))
|
||||||
|
|
||||||
|
await ctx.send("Successfully set nickname.")
|
||||||
|
|
||||||
@commands.guild_only()
|
@commands.guild_only()
|
||||||
@commands.check(check_if_staff)
|
@commands.check(check_if_staff)
|
||||||
@commands.command()
|
@commands.command()
|
||||||
async def delwarnid(self, ctx, target: int, idx: int):
|
async def userinfo(self, ctx, *, user: discord.Member):
|
||||||
"""Removes a specific warn from a user, staff only."""
|
"""Gets user info, staff only."""
|
||||||
log_channel = self.bot.get_channel(config.log_channel)
|
role = user.top_role.name
|
||||||
del_warn = self.delete_warns_from_id(str(target), idx)
|
if role == "@everyone":
|
||||||
# This is hell.
|
role = "@ everyone"
|
||||||
if isinstance(del_warn, discord.Embed):
|
await ctx.send(f"user = {user}\n"
|
||||||
await ctx.send(f"<@{target}> has a warning removed!")
|
f"id = {user.id}\n"
|
||||||
msg = f"🗑 **Deleted warn**: {ctx.author.mention} removed "\
|
f"avatar = {user.avatar_url}\n"
|
||||||
f"warn {idx} from <@{target}> "
|
f"bot = {user.bot}\n"
|
||||||
await log_channel.send(msg, embed=del_warn)
|
f"created_at = {user.created_at}\n"
|
||||||
|
f"display_name = {user.display_name}\n"
|
||||||
|
f"joined_at = {user.joined_at}\n"
|
||||||
|
f"activities = `{user.activities}`\n"
|
||||||
|
f"color = {user.colour}\n"
|
||||||
|
f"top_role = {role}\n")
|
||||||
|
|
||||||
|
@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)
|
||||||
|
|
||||||
|
@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:
|
else:
|
||||||
await ctx.send(del_warn)
|
await self.bot.change_presence(activity=None)
|
||||||
|
|
||||||
|
await ctx.send("Successfully set game.")
|
||||||
|
|
||||||
@commands.guild_only()
|
@commands.guild_only()
|
||||||
@commands.check(check_if_staff)
|
@commands.check(check_if_staff)
|
||||||
@commands.command()
|
@commands.command(aliases=["setbotnick", "botnick", "robotnick"])
|
||||||
async def clearreactsbyuser(self, ctx, user: discord.Member, *,
|
async def botnickname(self, ctx, *, nick: str = ""):
|
||||||
channel: discord.TextChannel = None,
|
"""Sets the bot's nickname, staff only.
|
||||||
limit: int = 50):
|
|
||||||
"""Clears reacts from a given user in the given channel, staff only."""
|
|
||||||
log_channel = self.bot.get_channel(config.log_channel)
|
|
||||||
if not channel:
|
|
||||||
channel = ctx.channel
|
|
||||||
count = 0
|
|
||||||
async for msg in channel.history(limit=limit):
|
|
||||||
for react in msg.reactions:
|
|
||||||
if await react.users().find(lambda u: u == user):
|
|
||||||
count += 1
|
|
||||||
async for u in react.users():
|
|
||||||
await msg.remove_reaction(react, u)
|
|
||||||
msg = f"✏️ **Cleared reacts**: {ctx.author.mention} cleared "\
|
|
||||||
f"{user.mention}'s reacts from the last {limit} messages "\
|
|
||||||
f"in {channel.mention}."
|
|
||||||
await ctx.channel.send(f"Cleared {count} unique reactions")
|
|
||||||
await log_channel.send(msg)
|
|
||||||
|
|
||||||
@commands.guild_only()
|
Just send .botnickname to wipe the nickname."""
|
||||||
@commands.check(check_if_staff)
|
|
||||||
@commands.command()
|
|
||||||
async def clearallreacts(self, ctx, *,
|
|
||||||
limit: int = 50,
|
|
||||||
channel: discord.TextChannel = None):
|
|
||||||
"""Clears all reacts in a given channel, staff only. Use with care."""
|
|
||||||
log_channel = self.bot.get_channel(config.log_channel)
|
|
||||||
if not channel:
|
|
||||||
channel = ctx.channel
|
|
||||||
count = 0
|
|
||||||
async for msg in channel.history(limit=limit):
|
|
||||||
if msg.reactions:
|
|
||||||
count += 1
|
|
||||||
await msg.clear_reactions()
|
|
||||||
msg = f"✏️ **Cleared reacts**: {ctx.author.mention} cleared all "\
|
|
||||||
f"reacts from the last {limit} messages in {channel.mention}."
|
|
||||||
await ctx.channel.send(f"Cleared reacts from {count} messages!")
|
|
||||||
await log_channel.send(msg)
|
|
||||||
|
|
||||||
@commands.guild_only()
|
|
||||||
@commands.check(check_if_staff)
|
|
||||||
@commands.command()
|
|
||||||
async def clearreactsinteractive(self, ctx):
|
|
||||||
"""Clears reacts interactively, staff only. Use with care."""
|
|
||||||
log_channel = self.bot.get_channel(config.log_channel)
|
|
||||||
|
|
||||||
msg_text = f"{ctx.author.mention}, react to the reactions you want "\
|
if nick:
|
||||||
f"to remove. React to this message when you're done."
|
await ctx.guild.me.edit(nick=nick, reason=str(ctx.author))
|
||||||
msg = await ctx.channel.send(msg_text)
|
|
||||||
|
|
||||||
tasks = []
|
|
||||||
|
|
||||||
def check(event):
|
|
||||||
# we only care about the user who is clearing reactions
|
|
||||||
if event.user_id != ctx.author.id:
|
|
||||||
return False
|
|
||||||
# this is how the user finishes
|
|
||||||
if event.message_id == msg.id:
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
# remove a reaction
|
|
||||||
async def impl():
|
|
||||||
msg = await self.bot \
|
|
||||||
.get_guild(event.guild_id) \
|
|
||||||
.get_channel(event.channel_id) \
|
|
||||||
.get_message(event.message_id)
|
|
||||||
def check_emoji(r):
|
|
||||||
if event.emoji.is_custom_emoji() == r.custom_emoji:
|
|
||||||
if event.emoji.is_custom_emoji():
|
|
||||||
return event.emoji.id == r.emoji.id
|
|
||||||
else:
|
|
||||||
# gotta love consistent APIs
|
|
||||||
return event.emoji.name == r.emoji
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
for reaction in filter(check_emoji, msg.reactions):
|
|
||||||
async for u in reaction.users():
|
|
||||||
await reaction.message.remove_reaction(reaction, u)
|
|
||||||
# schedule immediately
|
|
||||||
tasks.append(asyncio.create_task(impl()))
|
|
||||||
return False
|
|
||||||
|
|
||||||
try:
|
|
||||||
await self.bot.wait_for("raw_reaction_add",
|
|
||||||
timeout=120.0,
|
|
||||||
check=check)
|
|
||||||
except asyncio.TimeoutError:
|
|
||||||
await msg.edit(content = f"{msg_text} Timed out.")
|
|
||||||
else:
|
else:
|
||||||
await asyncio.gather(*tasks)
|
await ctx.guild.me.edit(nick=None, reason=str(ctx.author))
|
||||||
await msg.edit(content = f"{msg_text} Done!")
|
|
||||||
|
await ctx.send("Successfully set bot nickname.")
|
||||||
|
|
||||||
|
|
||||||
def setup(bot):
|
def setup(bot):
|
||||||
bot.add_cog(Mod(bot))
|
bot.add_cog(Mod(bot))
|
||||||
|
|
31
cogs/mod_note.py
Normal file
31
cogs/mod_note.py
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from helpers.checks import check_if_staff
|
||||||
|
from helpers.userlogs import userlog
|
||||||
|
|
||||||
|
|
||||||
|
class ModNote:
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
@commands.guild_only()
|
||||||
|
@commands.check(check_if_staff)
|
||||||
|
@commands.command(aliases=["addnote"])
|
||||||
|
async def note(self, ctx, target: discord.Member, *, note: str = ""):
|
||||||
|
"""Adds a note to a user, staff only."""
|
||||||
|
userlog(target.id, ctx.author, note,
|
||||||
|
"notes", target.name)
|
||||||
|
await ctx.send(f"{target.mention}: noted!")
|
||||||
|
|
||||||
|
@commands.guild_only()
|
||||||
|
@commands.check(check_if_staff)
|
||||||
|
@commands.command(aliases=["addnoteid"])
|
||||||
|
async def noteid(self, ctx, target: int, *, note: str = ""):
|
||||||
|
"""Adds a note to a user by userid, staff only."""
|
||||||
|
userlog(target, ctx.author, note,
|
||||||
|
"notes")
|
||||||
|
await ctx.send(f"{target.mention}: noted!")
|
||||||
|
|
||||||
|
|
||||||
|
def setup(bot):
|
||||||
|
bot.add_cog(ModNote(bot))
|
109
cogs/mod_reacts.py
Normal file
109
cogs/mod_reacts.py
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
import asyncio
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
import config
|
||||||
|
from helpers.checks import check_if_staff
|
||||||
|
|
||||||
|
|
||||||
|
class ModReact:
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
@commands.guild_only()
|
||||||
|
@commands.check(check_if_staff)
|
||||||
|
@commands.command()
|
||||||
|
async def clearreactsbyuser(self, ctx, user: discord.Member, *,
|
||||||
|
channel: discord.TextChannel = None,
|
||||||
|
limit: int = 50):
|
||||||
|
"""Clears reacts from a given user in the given channel, staff only."""
|
||||||
|
log_channel = self.bot.get_channel(config.log_channel)
|
||||||
|
if not channel:
|
||||||
|
channel = ctx.channel
|
||||||
|
count = 0
|
||||||
|
async for msg in channel.history(limit=limit):
|
||||||
|
for react in msg.reactions:
|
||||||
|
if await react.users().find(lambda u: u == user):
|
||||||
|
count += 1
|
||||||
|
async for u in react.users():
|
||||||
|
await msg.remove_reaction(react, u)
|
||||||
|
msg = f"✏️ **Cleared reacts**: {ctx.author.mention} cleared "\
|
||||||
|
f"{user.mention}'s reacts from the last {limit} messages "\
|
||||||
|
f"in {channel.mention}."
|
||||||
|
await ctx.channel.send(f"Cleared {count} unique reactions")
|
||||||
|
await log_channel.send(msg)
|
||||||
|
|
||||||
|
@commands.guild_only()
|
||||||
|
@commands.check(check_if_staff)
|
||||||
|
@commands.command()
|
||||||
|
async def clearallreacts(self, ctx, *,
|
||||||
|
limit: int = 50,
|
||||||
|
channel: discord.TextChannel = None):
|
||||||
|
"""Clears all reacts in a given channel, staff only. Use with care."""
|
||||||
|
log_channel = self.bot.get_channel(config.log_channel)
|
||||||
|
if not channel:
|
||||||
|
channel = ctx.channel
|
||||||
|
count = 0
|
||||||
|
async for msg in channel.history(limit=limit):
|
||||||
|
if msg.reactions:
|
||||||
|
count += 1
|
||||||
|
await msg.clear_reactions()
|
||||||
|
msg = f"✏️ **Cleared reacts**: {ctx.author.mention} cleared all "\
|
||||||
|
f"reacts from the last {limit} messages in {channel.mention}."
|
||||||
|
await ctx.channel.send(f"Cleared reacts from {count} messages!")
|
||||||
|
await log_channel.send(msg)
|
||||||
|
|
||||||
|
@commands.guild_only()
|
||||||
|
@commands.check(check_if_staff)
|
||||||
|
@commands.command()
|
||||||
|
async def clearreactsinteractive(self, ctx):
|
||||||
|
"""Clears reacts interactively, staff only. Use with care."""
|
||||||
|
msg_text = f"{ctx.author.mention}, react to the reactions you want "\
|
||||||
|
f"to remove. React to this message when you're done."
|
||||||
|
msg = await ctx.channel.send(msg_text)
|
||||||
|
|
||||||
|
tasks = []
|
||||||
|
|
||||||
|
def check(event):
|
||||||
|
# we only care about the user who is clearing reactions
|
||||||
|
if event.user_id != ctx.author.id:
|
||||||
|
return False
|
||||||
|
# this is how the user finishes
|
||||||
|
if event.message_id == msg.id:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
# remove a reaction
|
||||||
|
async def impl():
|
||||||
|
msg = await self.bot \
|
||||||
|
.get_guild(event.guild_id) \
|
||||||
|
.get_channel(event.channel_id) \
|
||||||
|
.get_message(event.message_id)
|
||||||
|
|
||||||
|
def check_emoji(r):
|
||||||
|
if event.emoji.is_custom_emoji() == r.custom_emoji:
|
||||||
|
if event.emoji.is_custom_emoji():
|
||||||
|
return event.emoji.id == r.emoji.id
|
||||||
|
else:
|
||||||
|
# gotta love consistent APIs
|
||||||
|
return event.emoji.name == r.emoji
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
for reaction in filter(check_emoji, msg.reactions):
|
||||||
|
async for u in reaction.users():
|
||||||
|
await reaction.message.remove_reaction(reaction, u)
|
||||||
|
# schedule immediately
|
||||||
|
tasks.append(asyncio.create_task(impl()))
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
await self.bot.wait_for("raw_reaction_add",
|
||||||
|
timeout=120.0,
|
||||||
|
check=check)
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
await msg.edit(content=f"{msg_text} Timed out.")
|
||||||
|
else:
|
||||||
|
await asyncio.gather(*tasks)
|
||||||
|
await msg.edit(content=f"{msg_text} Done!")
|
||||||
|
|
||||||
|
|
||||||
|
def setup(bot):
|
||||||
|
bot.add_cog(ModReact(bot))
|
181
cogs/mod_userlog.py
Normal file
181
cogs/mod_userlog.py
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
import config
|
||||||
|
import json
|
||||||
|
from helpers.checks import check_if_staff
|
||||||
|
from helpers.userlogs import get_userlog, set_userlog, userlog_event_types
|
||||||
|
|
||||||
|
|
||||||
|
class ModUserlog:
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
def get_userlog_embed_for_id(self, uid: str, name: str, own: bool = False,
|
||||||
|
event=""):
|
||||||
|
own_note = " Good for you!" if own else ""
|
||||||
|
wanted_events = ["warns", "bans", "kicks", "mutes"]
|
||||||
|
if event:
|
||||||
|
wanted_events = [event]
|
||||||
|
embed = discord.Embed(color=discord.Color.dark_red())
|
||||||
|
embed.set_author(name=f"Userlog for {name}")
|
||||||
|
userlog = get_userlog()
|
||||||
|
|
||||||
|
if uid not in userlog:
|
||||||
|
embed.description = f"There are none!{own_note} (no entry)"
|
||||||
|
embed.color = discord.Color.green()
|
||||||
|
return embed
|
||||||
|
|
||||||
|
for event_type in wanted_events:
|
||||||
|
if event_type in userlog[uid] and userlog[uid][event_type]:
|
||||||
|
event_name = userlog_event_types[event_type]
|
||||||
|
for idx, event in enumerate(userlog[uid][event_type]):
|
||||||
|
issuer = "" if own else f"Issuer: {event['issuer_name']} "\
|
||||||
|
f"({event['issuer_id']})\n"
|
||||||
|
embed.add_field(name=f"{event_name} {idx + 1}: "
|
||||||
|
f"{event['timestamp']}",
|
||||||
|
value=issuer + f"Reason: {event['reason']}",
|
||||||
|
inline=False)
|
||||||
|
|
||||||
|
if not own and "watch" in userlog[uid]:
|
||||||
|
watch_state = "" if userlog[uid]["watch"] else "NOT "
|
||||||
|
embed.set_footer(text=f"User is {watch_state}under watch.")
|
||||||
|
|
||||||
|
if not embed.fields:
|
||||||
|
embed.description = f"There are none!{own_note}"
|
||||||
|
embed.color = discord.Color.green()
|
||||||
|
return embed
|
||||||
|
|
||||||
|
def clear_event_from_id(self, uid: str, event_type):
|
||||||
|
userlog = get_userlog()
|
||||||
|
if uid not in userlog:
|
||||||
|
return f"<@{uid}> has no {event_type}!"
|
||||||
|
event_count = len(userlog[uid][event_type])
|
||||||
|
if not event_count:
|
||||||
|
return f"<@{uid}> has no {event_type}!"
|
||||||
|
userlog[uid][event_type] = []
|
||||||
|
set_userlog(json.dumps(userlog))
|
||||||
|
return f"<@{uid}> no longer has any {event_type}!"
|
||||||
|
|
||||||
|
def delete_event_from_id(self, uid: str, idx: int, event_type):
|
||||||
|
userlog = get_userlog()
|
||||||
|
if uid not in userlog:
|
||||||
|
return f"<@{uid}> has no {event_type}!"
|
||||||
|
event_count = len(userlog[uid][event_type])
|
||||||
|
if not event_count:
|
||||||
|
return f"<@{uid}> has no {event_type}!"
|
||||||
|
if idx > event_count:
|
||||||
|
return "Index is higher than "\
|
||||||
|
f"count ({event_count})!"
|
||||||
|
if idx < 1:
|
||||||
|
return "Index is below 1!"
|
||||||
|
event = userlog[uid][event_type][idx - 1]
|
||||||
|
embed = discord.Embed(color=discord.Color.dark_red(),
|
||||||
|
title=f"{event_type} {idx} on "
|
||||||
|
f"{event['timestamp']}",
|
||||||
|
description=f"Issuer: {event['issuer_name']}\n"
|
||||||
|
f"Reason: {event['reason']}")
|
||||||
|
del userlog[uid][event_type][idx - 1]
|
||||||
|
set_userlog(json.dumps(userlog))
|
||||||
|
return embed
|
||||||
|
|
||||||
|
@commands.guild_only()
|
||||||
|
@commands.check(check_if_staff)
|
||||||
|
@commands.command(name="userlog",
|
||||||
|
aliases=["listwarns", "getuserlog", "listuserlog"])
|
||||||
|
async def userlog_cmd(self, ctx, target: discord.Member):
|
||||||
|
"""Lists the userlog events for a user, staff only."""
|
||||||
|
embed = self.get_userlog_embed_for_id(str(target.id), str(target))
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
@commands.guild_only()
|
||||||
|
@commands.check(check_if_staff)
|
||||||
|
@commands.command(aliases=["listnotes", "usernotes"])
|
||||||
|
async def notes(self, ctx, target: discord.Member):
|
||||||
|
"""Lists the notes for a user, staff only."""
|
||||||
|
embed = self.get_userlog_embed_for_id(str(target.id), str(target),
|
||||||
|
event="notes")
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
@commands.guild_only()
|
||||||
|
@commands.command(aliases=["mywarns"])
|
||||||
|
async def myuserlog(self, ctx):
|
||||||
|
"""Lists your userlog events (warns etc)."""
|
||||||
|
embed = self.get_userlog_embed_for_id(str(ctx.author.id),
|
||||||
|
str(ctx.author), True)
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
@commands.guild_only()
|
||||||
|
@commands.check(check_if_staff)
|
||||||
|
@commands.command(aliases=["listwarnsid"])
|
||||||
|
async def userlogid(self, ctx, target: int):
|
||||||
|
"""Lists the userlog events for a user by ID, staff only."""
|
||||||
|
embed = self.get_userlog_embed_for_id(str(target), str(target))
|
||||||
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
|
@commands.guild_only()
|
||||||
|
@commands.check(check_if_staff)
|
||||||
|
@commands.command(aliases=["clearwarns"])
|
||||||
|
async def clearevent(self, ctx, target: discord.Member,
|
||||||
|
event="warns"):
|
||||||
|
"""Clears all events of given type for a user, staff only."""
|
||||||
|
log_channel = self.bot.get_channel(config.log_channel)
|
||||||
|
msg = self.clear_event_from_id(str(target.id), event)
|
||||||
|
await ctx.send(msg)
|
||||||
|
msg = f"🗑 **Cleared {event}**: {ctx.author.mention} cleared"\
|
||||||
|
f" all {event} events of {target.mention} | "\
|
||||||
|
f"{self.bot.escape_message(target)}"
|
||||||
|
await log_channel.send(msg)
|
||||||
|
|
||||||
|
@commands.guild_only()
|
||||||
|
@commands.check(check_if_staff)
|
||||||
|
@commands.command(aliases=["clearwarnsid"])
|
||||||
|
async def cleareventid(self, ctx, target: int, event="warns"):
|
||||||
|
"""Clears all events of given type for a userid, staff only."""
|
||||||
|
log_channel = self.bot.get_channel(config.log_channel)
|
||||||
|
msg = self.clear_event_from_id(str(target), event)
|
||||||
|
await ctx.send(msg)
|
||||||
|
msg = f"🗑 **Cleared {event}**: {ctx.author.mention} cleared"\
|
||||||
|
f" all {event} events of <@{target}> "
|
||||||
|
await log_channel.send(msg)
|
||||||
|
|
||||||
|
@commands.guild_only()
|
||||||
|
@commands.check(check_if_staff)
|
||||||
|
@commands.command(aliases=["delwarn"])
|
||||||
|
async def delevent(self, ctx, target: discord.Member, idx: int,
|
||||||
|
event="warns"):
|
||||||
|
"""Removes a specific event from a user, staff only."""
|
||||||
|
log_channel = self.bot.get_channel(config.log_channel)
|
||||||
|
del_event = self.delete_event_from_id(str(target.id), idx, event)
|
||||||
|
event_name = userlog_event_types[event].lower()
|
||||||
|
# This is hell.
|
||||||
|
if isinstance(del_event, discord.Embed):
|
||||||
|
await ctx.send(f"{target.mention} has a {event_name} removed!")
|
||||||
|
msg = f"🗑 **Deleted {event_name}**: "\
|
||||||
|
f"{ctx.author.mention} removed "\
|
||||||
|
f"{event_name} {idx} from {target.mention} | "\
|
||||||
|
f"{self.bot.escape_message(target)}"
|
||||||
|
await log_channel.send(msg, embed=del_event)
|
||||||
|
else:
|
||||||
|
await ctx.send(del_event)
|
||||||
|
|
||||||
|
@commands.guild_only()
|
||||||
|
@commands.check(check_if_staff)
|
||||||
|
@commands.command(aliases=["delwarnid"])
|
||||||
|
async def deleventid(self, ctx, target: int, idx: int, event="warns"):
|
||||||
|
"""Removes a specific event from a userid, staff only."""
|
||||||
|
log_channel = self.bot.get_channel(config.log_channel)
|
||||||
|
del_event = self.delete_event_from_id(str(target), idx, event)
|
||||||
|
event_name = userlog_event_types[event].lower()
|
||||||
|
# This is hell.
|
||||||
|
if isinstance(del_event, discord.Embed):
|
||||||
|
await ctx.send(f"<@{target}> has a {event_name} removed!")
|
||||||
|
msg = f"🗑 **Deleted {event_name}**: "\
|
||||||
|
f"{ctx.author.mention} removed "\
|
||||||
|
f"{event_name} {idx} from <@{target}> "
|
||||||
|
await log_channel.send(msg, embed=del_event)
|
||||||
|
else:
|
||||||
|
await ctx.send(del_event)
|
||||||
|
|
||||||
|
|
||||||
|
def setup(bot):
|
||||||
|
bot.add_cog(ModUserlog(bot))
|
|
@ -1 +1 @@
|
||||||
{}
|
{}
|
25
helpers/restrictions.py
Normal file
25
helpers/restrictions.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
def add_restriction(self, member, rst):
|
||||||
|
# from kurisu source, credits go to ihaveamac
|
||||||
|
with open("data/restrictions.json", "r") as f:
|
||||||
|
rsts = json.load(f)
|
||||||
|
if str(member.id) not in rsts:
|
||||||
|
rsts[str(member.id)] = []
|
||||||
|
if rst not in rsts[str(member.id)]:
|
||||||
|
rsts[str(member.id)].append(rst)
|
||||||
|
with open("data/restrictions.json", "w") as f:
|
||||||
|
json.dump(rsts, f)
|
||||||
|
|
||||||
|
|
||||||
|
def remove_restriction(self, member, rst):
|
||||||
|
# from kurisu source, credits go to ihaveamac
|
||||||
|
with open("data/restrictions.json", "r") as f:
|
||||||
|
rsts = json.load(f)
|
||||||
|
if str(member.id) not in rsts:
|
||||||
|
rsts[str(member.id)] = []
|
||||||
|
if rst in rsts[str(member.id)]:
|
||||||
|
rsts[str(member.id)].remove(rst)
|
||||||
|
with open("data/restrictions.json", "w") as f:
|
||||||
|
json.dump(rsts, f)
|
45
helpers/userlogs.py
Normal file
45
helpers/userlogs.py
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
|
||||||
|
userlog_event_types = {"warns": "Warn",
|
||||||
|
"bans": "Ban",
|
||||||
|
"kicks": "Kick",
|
||||||
|
"mutes": "Mute",
|
||||||
|
"notes": "Note"}
|
||||||
|
|
||||||
|
|
||||||
|
def get_userlog():
|
||||||
|
with open("data/warnsv2.json", "r") as f:
|
||||||
|
return json.load(f)
|
||||||
|
|
||||||
|
|
||||||
|
def set_userlog(contents):
|
||||||
|
with open("data/warnsv2.json", "w") as f:
|
||||||
|
f.write(contents)
|
||||||
|
|
||||||
|
|
||||||
|
def userlog(uid, issuer, reason, event_type, uname: str = ""):
|
||||||
|
with open("data/warnsv2.json", "r") as f:
|
||||||
|
userlogs = json.load(f)
|
||||||
|
uid = str(uid)
|
||||||
|
if uid not in userlogs:
|
||||||
|
userlogs[uid] = {"warns": [],
|
||||||
|
"mutes": [],
|
||||||
|
"kicks": [],
|
||||||
|
"bans": [],
|
||||||
|
"notes": [],
|
||||||
|
"watch": False,
|
||||||
|
"name": "n/a"}
|
||||||
|
if uname:
|
||||||
|
userlogs[uid]["name"] = uname
|
||||||
|
timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
|
||||||
|
log_data = {"issuer_id": issuer.id,
|
||||||
|
"issuer_name": f"{issuer}",
|
||||||
|
"reason": reason,
|
||||||
|
"timestamp": timestamp}
|
||||||
|
if event_type not in userlogs[uid]:
|
||||||
|
userlogs[uid][event_type] = []
|
||||||
|
userlogs[uid][event_type].append(log_data)
|
||||||
|
with open("data/warnsv2.json", "w") as f:
|
||||||
|
json.dump(userlogs, f)
|
||||||
|
return len(userlogs[uid][event_type])
|
Loading…
Reference in a new issue