college-bot-v1/cogs/mod.py

164 lines
6.7 KiB
Python
Raw Normal View History

2023-01-19 14:04:28 +00:00
from datetime import datetime
2023-11-04 17:18:39 +00:00
from typing import Sized
2023-01-19 14:04:28 +00:00
2022-10-04 16:20:01 +01:00
import discord
from discord.ext import commands
2023-11-04 17:18:39 +00:00
from utils import BannedStudentID, JimmyBans, Student, get_or_none, owner_or_admin
2023-04-18 17:42:01 +01:00
class LimitedList(list):
"""FIFO Limited list"""
2023-11-04 17:18:39 +00:00
2023-04-18 17:42:01 +01:00
def __init__(self, iterable: Sized = None, size: int = 5000):
if iterable:
assert len(iterable) <= size, "Initial iterable too big."
super().__init__(iterable or [])
self._max_size = size
def append(self, __object) -> None:
if len(self) + 1 >= self._max_size:
self.pop(0)
super().append(__object)
def __add__(self, other):
if len(other) > self._max_size:
raise ValueError("Other is too large")
elif len(other) == self._max_size:
self.clear()
super().__add__(other)
else:
for item in other:
self.append(item)
2022-10-04 16:20:01 +01:00
class Mod(commands.Cog):
def __init__(self, bot):
self.bot = bot
2023-04-18 17:42:01 +01:00
self.cache = LimitedList()
@commands.Cog.listener()
async def on_message_delete(self, message: discord.Message):
self.cache.append(message)
2022-10-04 16:20:01 +01:00
@commands.user_command(name="Ban Account's B Number")
@discord.default_permissions(ban_members=True)
async def ban_student_id(self, ctx: discord.ApplicationContext, member: discord.Member):
"""Bans a student ID from registering. Also bans an account associated with it."""
await ctx.defer(ephemeral=True)
student_id = await get_or_none(Student, user_id=member.id)
if student_id is None:
return await ctx.respond("\N{cross mark} Unknown B number (is the user verified yet?)", ephemeral=True)
ban = await get_or_none(BannedStudentID, student_id=student_id.id)
if ban is None:
ban = await BannedStudentID.objects.create(
student_id=student_id.id,
associated_account=member.id,
)
2022-11-28 17:30:44 +00:00
await member.ban(reason=f"Banned ID {ban.student_id} by {ctx.user}")
2022-10-04 16:20:01 +01:00
return await ctx.respond(
2022-10-30 16:31:38 +00:00
f"\N{white heavy check mark} Banned {ban.student_id} (and {member.mention})", ephemeral=True
2022-10-04 16:20:01 +01:00
)
@commands.slash_command(name="unban-student-number")
@discord.default_permissions(ban_members=True)
async def unban_student_id(self, ctx: discord.ApplicationContext, student_id: str):
"""Unbans a student ID and the account associated with it."""
student_id = student_id.upper()
ban = await get_or_none(BannedStudentID, student_id=student_id)
if not ban:
return await ctx.respond("\N{cross mark} That student ID isn't banned.")
await ctx.defer()
user_id = ban.associated_account
await ban.delete()
if not user_id:
2022-10-04 16:21:50 +01:00
return await ctx.respond(f"\N{white heavy check mark} Unbanned {student_id}. No user to unban.")
2022-10-04 16:20:01 +01:00
else:
try:
2022-11-28 17:30:44 +00:00
await ctx.guild.unban(discord.Object(user_id), reason=f"Unbanned by {ctx.user}")
2022-10-04 16:20:01 +01:00
except discord.HTTPException as e:
return await ctx.respond(
f"\N{white heavy check mark} Unbanned {student_id}. Failed to unban {user_id} - HTTP {e.status}."
)
else:
2022-10-30 16:31:38 +00:00
return await ctx.respond(f"\N{white heavy check mark} Unbanned {student_id}. Unbanned {user_id}.")
2022-10-04 16:20:01 +01:00
2023-01-19 14:04:28 +00:00
@commands.slash_command(name="block")
@owner_or_admin()
2023-02-09 13:44:49 +00:00
async def block_user(self, ctx: discord.ApplicationContext, user: discord.Member, reason: str, until: str):
2023-01-19 14:04:28 +00:00
"""Blocks a user from using the bot."""
await ctx.defer()
2023-01-26 15:14:37 +00:00
date = datetime.utcnow()
_time = until
try:
date, _time = until.split(" ")
except ValueError:
pass
else:
try:
date = datetime.strptime(date, "%d/%m/%Y")
except ValueError:
return await ctx.respond("Invalid date format. Use `DD/MM/YYYY`.")
2023-01-19 14:04:28 +00:00
try:
2023-01-26 15:15:19 +00:00
hour, minute = map(int, _time.split(":"))
2023-01-19 14:04:28 +00:00
except ValueError:
return await ctx.respond("\N{cross mark} Invalid time format. Use HH:MM.")
2023-01-26 15:14:37 +00:00
end = date.replace(hour=hour, minute=minute)
2023-01-19 14:04:28 +00:00
# get an entry for the user's ID, and if it doesn't exist, create it. Otherwise, alert the user.
entry = await get_or_none(JimmyBans, user_id=user.id)
if entry is None:
await JimmyBans.objects.create(user_id=user.id, reason=reason, until=end.timestamp())
else:
return await ctx.respond("\N{cross mark} That user is already blocked.")
await ctx.respond(f"\N{white heavy check mark} Blocked {user.mention} until {discord.utils.format_dt(end)}.")
@commands.slash_command(name="unblock")
@owner_or_admin()
async def unblock_user(self, ctx: discord.ApplicationContext, user: discord.Member):
"""Unblocks a user from using the bot."""
await ctx.defer()
entry = await get_or_none(JimmyBans, user_id=user.id)
if entry is None:
return await ctx.respond("\N{cross mark} That user isn't blocked.")
await entry.delete()
await ctx.respond(f"\N{white heavy check mark} Unblocked {user.mention}.")
2023-04-18 17:09:54 +01:00
@commands.command()
async def undelete(self, ctx: commands.Context, user: discord.User, *, query: str = None):
"""Searches through the message cache to see if there's any deleted messages."""
2023-04-18 17:42:01 +01:00
for message in self.cache:
2023-04-18 17:09:54 +01:00
message: discord.Message
if message.author == user:
query_ = query.lower() if query else None
2023-11-04 17:18:39 +00:00
content_ = str(message.clean_content or "").lower()
2023-04-18 17:11:33 +01:00
if query_ is not None and (query_ in content_ or content_ in query_):
2023-04-18 17:09:54 +01:00
break
else:
return await ctx.reply("\N{cross mark} No matches in cache.")
embeds = [
discord.Embed(title="Message found!"),
discord.Embed(
description=message.content,
colour=message.author.colour,
timestamp=message.created_at,
fields=[
2023-11-04 17:18:39 +00:00
discord.EmbedField("Attachment count", str(len(message.attachments)), False),
discord.EmbedField("Location", str(message.channel.mention)),
2023-04-18 17:09:54 +01:00
discord.EmbedField(
"Times",
f"Created: {discord.utils.format_dt(message.created_at, 'R')} | Edited: "
2023-11-04 17:18:39 +00:00
f"{'None' if message.edited_at is None else discord.utils.format_dt(message.edited_at, 'R')}",
),
],
).set_author(name=message.author.display_name, icon_url=message.author.display_avatar.url),
2023-04-18 17:09:54 +01:00
]
await ctx.reply(embeds=embeds)
2022-10-04 16:20:01 +01:00
def setup(bot):
bot.add_cog(Mod(bot))