feat(shard): ✨ Add p.bans command for moderators to see a user's bans.

This commit is contained in:
2025-03-15 23:26:19 -03:00
parent 7e4e354819
commit 481fba860e
10 changed files with 477 additions and 244 deletions
+5 -2
View File
@@ -21,8 +21,6 @@ class Payphone(commands.AutoShardedBot):
host=constants.REDIS_HOST, port=constants.REDIS_PORT, decode_responses=True
)
owner_id = 657091104877051907
def __init__(self):
intents = discord.Intents.default()
intents.guilds = True
@@ -49,6 +47,11 @@ class Payphone(commands.AutoShardedBot):
self.call_handler = calls.CallHandler(self)
self.owner_ids = [
657091104877051907, # Anastasia
1338608911208419471, # Rafael
]
async def on_ready(self) -> None:
"""Runs when the bot has finished initializing."""
+78 -2
View File
@@ -1,13 +1,13 @@
from datetime import datetime, timedelta, timezone
import discord
from discord.ext import commands
from discord.ext import commands, pages
from payphone.db import models
from payphone.bot import Payphone
from payphone.cogs import base
from payphone.cogs.admin import embeds, views
from payphone.core import checks
from payphone.core import checks, constants, formatting
class Admin(base.Cog):
@@ -147,6 +147,82 @@ class Admin(base.Cog):
embed=embeds.report_embed(report), view=views.ReportView(self.bot, report)
)
@commands.command()
@checks.is_moderator()
async def bans(self, ctx: commands.Context, user: discord.User | int) -> None:
"""Shows all bans of a specific user.
Options:
- `<user>`: The user to show the bans of.
Permissions:
- Bot Moderator
"""
user_id = user if isinstance(user, int) else user.id
bans = (
await models.Ban.filter(user_id=user_id)
.prefetch_related("report", "created_by")
.order_by("-created_at")
)
if not bans:
await ctx.send(f"<@!{user_id}> has no bans.")
return
await pages.Paginator(
[
(
discord.Embed(
color=constants.PRIMARY_COLOR,
title=f"Ban #{ban.id}",
description=formatting.trim(ban.report.message_content, 500),
author=discord.EmbedAuthor(
name=ban.report.user_name,
icon_url=ban.report.user_avatar_url,
),
fields=[
discord.EmbedField(
name="Banned Until",
value=(
f"<t:{int(ban.expires_at.timestamp())}> (<t:{int(ban.expires_at.timestamp())}:R>)"
if ban.expires_at
else "Forever"
),
),
discord.EmbedField(
name="User Avatar",
value=f"[Click to open avatar URL](<{ban.report.user_avatar_url}>)",
),
]
+ (
[
discord.EmbedField(
name="Replying To",
value=f'"{formatting.trim(ban.report.reply_message_content)}" by {ban.report.reply_user_name}',
)
]
if ban.report.reply_message_content
else []
),
thumbnail=ban.report.user_avatar_url,
footer=discord.EmbedFooter(
text=f"Banned by {(await self.bot.get_or_fetch_user(ban.created_by.id)).display_name}"
),
)
if ban.report
else discord.Embed(
color=constants.PRIMARY_COLOR,
title=f"Ban #{ban.id}",
description=f"The user was banned manually by <@!{ban.created_by.id}> <t:{int(ban.created_at.timestamp())}:R>.",
)
)
for ban in bans
],
author_check=True,
).send(ctx)
def setup(bot: Payphone) -> None:
"""Loads the Admin cog into the bot.
+2 -8
View File
@@ -88,11 +88,8 @@ class ReportView(discord.ui.View):
name="User Name",
value=self.report.user_name,
),
discord.EmbedField(
name="User Avatar",
value=f"[Click to open your avatar URL](<{self.report.user_avatar_url}>)",
),
],
thumbnail=self.report.user_avatar_url,
footer=discord.EmbedFooter(
text="⚠️ Repeating this action will result in a ban."
),
@@ -142,10 +139,6 @@ class ReportView(discord.ui.View):
name="User Name",
value=self.report.user_name,
),
discord.EmbedField(
name="User Avatar",
value=f"[Click to open your avatar URL](<{self.report.user_avatar_url}>)",
),
discord.EmbedField(
name="Expires At",
value=(
@@ -156,6 +149,7 @@ class ReportView(discord.ui.View):
),
),
],
thumbnail=self.report.user_avatar_url,
footer=discord.EmbedFooter(
text=(
"⚠️ In case you get banned again, your ban will last longer. Multiple bans will result in a permanent ban."
+24
View File
@@ -496,6 +496,20 @@ class Calls(base.Cog):
await ctx.send_response("✅ The message has been reported.", ephemeral=True)
replying_to = (
await self.bot.get_partial_messageable(
message.reference.channel_id
).fetch_message(message.reference.message_id)
if message.reference and not message.reference.cached_message
else (
message.reference.cached_message
if message.reference and message.reference.cached_message
else None
)
)
self.bot.log.info(replying_to)
await models.Report.update_or_create(
message_id=message_id,
defaults={
@@ -504,6 +518,16 @@ class Calls(base.Cog):
"user_name": message.author.display_name,
"user_avatar_url": message.author.display_avatar.url,
"message_content": message.content,
"reply_message_content": (
replying_to.clean_content if replying_to else None
),
"reply_user_id": (replying_to.author.id if replying_to else None),
"reply_user_name": (
replying_to.author.display_name if replying_to else None
),
"reply_user_avatar_url": (
replying_to.author.display_avatar.url if replying_to else None
),
},
)
@@ -0,0 +1,25 @@
from tortoise import BaseDBAsyncClient
async def upgrade(db: BaseDBAsyncClient) -> str:
return """
DROP INDEX "idx_channel_server__d940e4";
DROP INDEX "idx_ban_user_id_37a9cf";
ALTER TABLE "ban" ALTER COLUMN "report_id" TYPE BIGINT USING "report_id"::BIGINT;
ALTER TABLE "ban" ALTER COLUMN "report_id" TYPE BIGINT USING "report_id"::BIGINT;
ALTER TABLE "ban" ALTER COLUMN "report_id" TYPE BIGINT USING "report_id"::BIGINT;
ALTER TABLE "ban" ALTER COLUMN "report_id" TYPE BIGINT USING "report_id"::BIGINT;
CREATE INDEX "idx_ban_user_id_37a9cf" ON "ban" ("user_id", "expires_at");;
CREATE INDEX "idx_channel_server__d940e4" ON "channel" ("server_id", "is_enabled");;"""
async def downgrade(db: BaseDBAsyncClient) -> str:
return """
DROP INDEX "idx_channel_server__d940e4";
DROP INDEX "idx_ban_user_id_37a9cf";
ALTER TABLE "ban" ALTER COLUMN "report_id" TYPE INT USING "report_id"::INT;
ALTER TABLE "ban" ALTER COLUMN "report_id" TYPE INT USING "report_id"::INT;
ALTER TABLE "ban" ALTER COLUMN "report_id" TYPE INT USING "report_id"::INT;
ALTER TABLE "ban" ALTER COLUMN "report_id" TYPE INT USING "report_id"::INT;
CREATE INDEX "idx_ban_user_id_37a9cf" ON "ban" ("user_id", "expires_at");;
CREATE INDEX "idx_channel_server__d940e4" ON "channel" ("server_id", "is_enabled");;"""
@@ -0,0 +1,15 @@
from tortoise import BaseDBAsyncClient
async def upgrade(db: BaseDBAsyncClient) -> str:
return """
ALTER TABLE "report" ADD "reply_user_name" TEXT;
ALTER TABLE "report" ADD "reply_message_content" TEXT;
ALTER TABLE "report" ADD "reply_user_avatar_url" TEXT;"""
async def downgrade(db: BaseDBAsyncClient) -> str:
return """
ALTER TABLE "report" DROP COLUMN "reply_user_name";
ALTER TABLE "report" DROP COLUMN "reply_message_content";
ALTER TABLE "report" DROP COLUMN "reply_user_avatar_url";"""
@@ -0,0 +1,11 @@
from tortoise import BaseDBAsyncClient
async def upgrade(db: BaseDBAsyncClient) -> str:
return """
ALTER TABLE "report" ADD "reply_user_id" BIGINT;"""
async def downgrade(db: BaseDBAsyncClient) -> str:
return """
ALTER TABLE "report" DROP COLUMN "reply_user_id";"""
+6
View File
@@ -14,12 +14,18 @@ class Report(models.Model):
A report of a message.
"""
id = fields.BigIntField(pk=True)
message_id = fields.BigIntField(unique=True)
message_content = fields.TextField()
channel_id = fields.BigIntField()
user_id = fields.BigIntField()
user_name = fields.TextField()
user_avatar_url = fields.TextField()
reply_message_content = fields.TextField(null=True, default=None)
reply_user_id = fields.BigIntField(null=True)
reply_user_name = fields.TextField(null=True, default=None)
reply_user_avatar_url = fields.TextField(null=True, default=None)
created_at = fields.DatetimeField(auto_now_add=True)
resolved = fields.BooleanField(default=False, index=True)
resolved_at = fields.DatetimeField(null=True)