Add student ID moderation

This commit is contained in:
EEKIM10 2022-10-04 16:20:01 +01:00
parent 1aa2f4c510
commit 89daf7c762
6 changed files with 125 additions and 5 deletions

View file

@ -4,7 +4,7 @@
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/venv" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="jdk" jdkName="Python 3.10 (the-hi5-group)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

63
cogs/mod.py Normal file
View file

@ -0,0 +1,63 @@
import discord
from discord.ext import commands
from utils import Student, get_or_none, BannedStudentID
import orm
class Mod(commands.Cog):
def __init__(self, bot):
self.bot = bot
@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,
)
await member.ban(reason=f"Banned ID {ban.student_id} by {ctx.author}")
return await ctx.respond(
f"\N{white heavy check mark} Banned {ban.student_id} (and {member.mention})",
ephemeral=True
)
@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:
return await ctx.respond(f"\N{white heavy checkmark} Unbanned {student_id}. No user to unban.")
else:
try:
await ctx.guild.unban(
discord.Object(user_id),
reason=f"Unbanned by {ctx.author}"
)
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:
return await ctx.respond(
f"\N{white heavy check mark} Unbanned {student_id}. Unbanned {user_id}."
)
def setup(bot):
bot.add_cog(Mod(bot))

View file

@ -2,7 +2,7 @@ import discord
import orm
import re
from discord.ext import commands
from utils import send_verification_code, VerifyCode, Student, console
from utils import send_verification_code, VerifyCode, Student, console, get_or_none, BannedStudentID
import config
@ -45,7 +45,17 @@ class VerifyCog(commands.Cog):
return
if not re.match(r"^B\d{6}$", st):
return await interaction.response.send_message("\N{cross mark} Invalid student ID.")
return await interaction.response.send_message(
"\N{cross mark} Invalid student ID.",
delete_after=60
)
ex = await get_or_none(Student, id=st)
if ex:
return await interaction.response.send_message(
"\N{cross mark} Student ID is already associated.",
delete_after=60
)
_code = await send_verification_code(ctx.author, st)
console.log(f"Sending verification email to {ctx.author} ({ctx.author.id}/{st})...")
@ -74,6 +84,12 @@ class VerifyCog(commands.Cog):
"\N{cross mark} Invalid or unknown verification code. Try again!", ephemeral=True
)
else:
ban = await get_or_none(BannedStudentID, student_id=existing.student_id)
if ban is not None:
return await ctx.author.ban(
reason=f"Attempted to verify with banned student ID {ban.student_id}"
f" (originally associated with account {ban.associated_account})"
)
await Student.objects.create(id=existing.student_id, user_id=ctx.author.id)
await existing.delete()
role = discord.utils.find(lambda r: r.name.lower() == "verified", guild.roles)

View file

@ -9,6 +9,7 @@ bot = commands.Bot(
)
bot.load_extension("jishaku")
bot.load_extension("cogs.verify")
bot.load_extension("cogs.mod")
bot.loop.run_until_complete(registry.create_all())

View file

@ -1,4 +1,4 @@
py-cord==2.1.3
py-cord==2.2.0
aiosmtplib==1.1.7
orm[sqlite]==0.3.1
httpx==0.23.0

View file

@ -1,5 +1,6 @@
import datetime
import uuid
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Optional, TypeVar
import orm
from databases import Database
@ -9,9 +10,32 @@ from pathlib import Path
os.chdir(Path(__file__).parent.parent)
__all__ = [
"registry",
"get_or_none"
]
_models = [
"VerifyCode",
"Student",
"BannedStudentID"
]
__all__ += _models
T = TypeVar('T')
T_co = TypeVar("T_co", covariant=True)
registry = orm.ModelRegistry(Database("sqlite:///main.db"))
async def get_or_none(model: T, **kw) -> Optional[T_co]:
"""Returns none or the required thing."""
try:
return await model.objects.get(**kw)
except orm.NoMatch:
return
class VerifyCode(orm.Model):
registry = registry
tablename = "codes"
@ -40,3 +64,19 @@ class Student(orm.Model):
entry_id: uuid.UUID
id: str
user_id: int
class BannedStudentID(orm.Model):
registry = registry
tablename = "banned"
fields = {
"entry_id": orm.UUID(primary_key=True, default=uuid.uuid4),
"student_id": orm.String(min_length=7, max_length=7, unique=True),
"associated_account": orm.BigInteger(default=None),
"banned_at_timestamp": orm.Float(default=lambda: datetime.datetime.utcnow().timestamp())
}
if TYPE_CHECKING:
entry_id: uuid.UUID
student_id: str
associated_account: Optional[int]
banned_at_timestamp: float