fix(bot): ✨ Improve p.stats.

This commit is contained in:
Nyeki.py
2024-10-17 23:37:13 -03:00
parent 62e2d30fdf
commit 0fbf7d86dc
10 changed files with 191 additions and 45 deletions
+5 -3
View File
@@ -51,9 +51,11 @@ async def ReplyEmbed(
embed = discord.Embed( embed = discord.Embed(
color=constants.EMBED_COLOR, color=constants.EMBED_COLOR,
description=formatting.trim(last_content.content) description=(
if last_content.was_propagated or is_this_channel formatting.trim(last_content.content)
else "*This message was censored.*", if last_content.was_propagated or is_this_channel
else "*This message was censored.*"
),
author=discord.EmbedAuthor( author=discord.EmbedAuthor(
name=f"Replied to {author_name}", name=f"Replied to {author_name}",
icon_url=author_avatar_url, icon_url=author_avatar_url,
+90 -17
View File
@@ -1,3 +1,5 @@
from typing import Awaitable
from datetime import datetime, timezone, timedelta from datetime import datetime, timezone, timedelta
import sys import sys
@@ -13,7 +15,7 @@ from payphone import bot
from payphone.db import models, utils from payphone.db import models, utils
from payphone.cogs import base from payphone.cogs import base
from payphone.cogs.mods import embeds, views from payphone.cogs.mods import embeds, views
from payphone.core import checks, converters, constants from payphone.core import checks, converters, constants, formatting as fmt
class Mods(base.Cog): class Mods(base.Cog):
@@ -291,29 +293,100 @@ class Mods(base.Cog):
@commands.command() @commands.command()
@commands.is_owner() @commands.is_owner()
async def stats(self, ctx: commands.Context) -> None: async def stats(
self, ctx: commands.Context, iterations: int = 5, wait: int = 5
) -> None:
""" """
Shows all Payphone's stats. Shows all Payphone's stats.
Options:
- `<iterations>`: The amount of iterations (to display progress). Defaults to 5.
- `<wait>`: The amount of seconds to wait between iterations. Defaults to 5.
""" """
stats = [ stats = [
f"On-call Channels: {await self.bot.redis.scard(constants.CHANNELS_ONCALL_SET)}", (
f"Searching Channels: {await self.bot.redis.scard(constants.CHANNELS_SEARCH_QUEUE)}", "On-call Channels",
f"Messages: {await models.Message.all().count()}", lambda: self.bot.redis.scard(constants.CHANNELS_ONCALL_SET),
f"Message Contents: {await models.MessageContent.all().count()}", ),
f"Calls: {await models.Call.all().count()}", (
f"Ongoing Calls: {await models.Call.filter(ended_at=None).count()}", "Searching Channels",
f"Bans: {await models.Ban.all().count()}", lambda: self.bot.redis.scard(constants.CHANNELS_SEARCH_QUEUE),
f"Reports: {await models.Report.all().count()}", ),
f"On-review Reports: {await models.Report.filter(status=models.ReportStatus.ON_REVIEW).count()}", (
f"Users: {await models.User.all().count()}", "Messages",
f"Profiles: {await models.Profile.all().count()}", lambda: models.Message.all().count(),
f"Servers: {await models.Server.all().count()}", ),
f"Shards: {self.bot.shard_count}", (
f"Current Shard: {ctx.guild.shard_id + 1}", "Message Contents",
lambda: models.MessageContent.all().count(),
),
("Calls", lambda: models.Call.all().count()),
(
"Ongoing Calls",
lambda: models.Call.filter(ended_at=None).count(),
),
("Bans", lambda: models.Ban.all().count()),
("Reports", lambda: models.Report.all().count()),
(
"On-review Reports",
lambda: models.Report.filter(
status=models.ReportStatus.ON_REVIEW
).count(),
),
("Users", lambda: models.User.all().count()),
(
"Profiles",
lambda: models.Profile.all().count(),
),
("Servers", lambda: models.Server.all().count()),
("Shards", lambda: self.bot.shard_count),
("Current Shards", lambda: ctx.guild.shard_id + 1),
] ]
await ctx.send(f"```\n{"\n".join(stats)}\n```") rows = [[stat[0]] for stat in stats]
rows_with_diff = [[stat[0]] for stat in stats]
i = 0
message = None
while i < iterations:
i += 1
for stat_i, stat in enumerate(stats):
value = stat[1]()
if isinstance(value, Awaitable):
value = await value
rows[stat_i].append(value)
prev_value = rows[stat_i][-2]
if isinstance(prev_value, str):
rows_with_diff[stat_i].append(value)
else:
diff = value - prev_value
rows_with_diff[stat_i].append(
str(value)
+ (f" ({"+" if diff > 0 else ""}{diff})" if diff != 0 else "")
)
table = fmt.monospace_table(
rows_with_diff,
[""] + [f"{wait * j}s" for j in range(i)],
padding=2,
)
if message is None:
message = await ctx.send(f"```\n{table}\n```")
else:
message = await message.edit(f"```\n{table}\n```")
if i < iterations:
await asyncio.sleep(wait)
def setup(b: bot.Payphone) -> None: def setup(b: bot.Payphone) -> None:
+10 -6
View File
@@ -28,15 +28,19 @@ class BanNotificationEmbed(discord.Embed):
), ),
discord.EmbedField( discord.EmbedField(
name="Expires At", name="Expires At",
value=f"<t:{int(ban.expires_at.timestamp())}:F> (<t:{int(ban.expires_at.timestamp())}:R>)" value=(
if ban.expires_at f"<t:{int(ban.expires_at.timestamp())}:F> (<t:{int(ban.expires_at.timestamp())}:R>)"
else "*Does not expire.*", if ban.expires_at
else "*Does not expire.*"
),
), ),
discord.EmbedField( discord.EmbedField(
name="Appeal", name="Appeal",
value="*You haven't appealed this ban.*" value=(
if ban.appeal is None "*You haven't appealed this ban.*"
else ban.appeal, if ban.appeal is None
else ban.appeal
),
), ),
], ],
author=bot.embed_author, author=bot.embed_author,
+2 -2
View File
@@ -186,7 +186,7 @@ class ReportView(discord.ui.View):
await interaction.response.edit_message( await interaction.response.edit_message(
content="✅ You're up to date! No reports left to check.", content="✅ You're up to date! No reports left to check.",
embed=None, embed=None,
view=None view=None,
) )
return return
@@ -218,7 +218,7 @@ class ReportView(discord.ui.View):
await interaction.response.edit_message( await interaction.response.edit_message(
content="✅ You're up to date! No reports left to check.", content="✅ You're up to date! No reports left to check.",
embed=None, embed=None,
view=None view=None,
) )
return return
+5 -3
View File
@@ -175,9 +175,11 @@ class Users(base.Cog):
logs += f"- `{call_id}`: " logs += f"- `{call_id}`: "
participant_names = ", ".join( participant_names = ", ".join(
call_rs.display_name (
if call_rs.channel_id != data["user_rs"].channel_id call_rs.display_name
else call_rs.profile.name if call_rs.channel_id != data["user_rs"].channel_id
else call_rs.profile.name
)
for call_rs in data["others_rs"] + [data["user_rs"]] for call_rs in data["others_rs"] + [data["user_rs"]]
) )
+3 -3
View File
@@ -246,16 +246,16 @@ def moderate(message: str) -> str:
match = next(PATTERN.finditer(message), None) match = next(PATTERN.finditer(message), None)
if match is not None: if match is not None:
return message[match.start():match.end()] return message[match.start() : match.end()]
match = next(URL_PATTERN.finditer(message), None) match = next(URL_PATTERN.finditer(message), None)
if match is not None: if match is not None:
return message[match.start():match.end()] return message[match.start() : match.end()]
match = next(INVITES_PATTERN.finditer(message), None) match = next(INVITES_PATTERN.finditer(message), None)
if match is not None: if match is not None:
return message[match.start():match.end()] return message[match.start() : match.end()]
return None return None
+3 -3
View File
@@ -27,9 +27,9 @@ def is_unbanned():
async def predicate(ctx: commands.Context) -> bool: async def predicate(ctx: commands.Context) -> bool:
if await ctx.bot.is_banned(ctx.author): if await ctx.bot.is_banned(ctx.author):
raise exceptions.BannedError() raise exceptions.BannedError()
return True return True
return commands.check(predicate) return commands.check(predicate)
@@ -45,7 +45,7 @@ def is_on_call():
if not is_on_call: if not is_on_call:
raise exceptions.NotOnCallError() raise exceptions.NotOnCallError()
return True return True
return commands.check(predicate) return commands.check(predicate)
+67 -3
View File
@@ -56,6 +56,68 @@ def monospace_grid(values: list[str], space: int = 14) -> str:
return "```" + "".join([v + " " * (space - len(v)) for v in values]) + "```" return "```" + "".join([v + " " * (space - len(v)) for v in values]) + "```"
def monospace_table(
rows: list[tuple],
headers: list | None = None,
column_separator: str = "|",
header_separator: str = "-",
intersection: str = "+",
padding: int = 1,
) -> str:
"""Creates a monospace table.
Args:
rows (list[tuple]): The rows.
headers (list | None, optional): The headers.
column_separator (str, optional): The column separator. Defaults to "|".
header_separator (str, optional): The header separator. Defaults to "-".
intersection (str, optional): The intersection character where column and row separators meet.
padding (int, optional): The padding that each column has at its sides.
Returns:
str: The monospace table.
"""
max_sizes = [
max(
*(
[len(str(row[i])) for row in rows]
+ ([len(headers[i])] if headers is not None else [])
)
)
for i in range(len(rows[0]))
]
def format_row(row: list) -> str:
return column_separator.join(
[
(" " * padding)
+ str(col)
+ (" " * (max_sizes[i] - len(str(col))))
+ (" " * padding)
for i, col in enumerate(row)
]
)
formatted_rows = []
for row in rows:
formatted_rows.append(format_row(row))
table = "\n".join(formatted_rows)
if headers is not None:
header = format_row(headers)
separator = intersection.join(
[header_separator * (size + padding * 2) for size in max_sizes]
)
table = f"{header}\n{separator}\n{table}"
return table
def clean( def clean(
message: discord.Message, call_rss: list[models.CallUserChannelRelationship] message: discord.Message, call_rss: list[models.CallUserChannelRelationship]
) -> str: ) -> str:
@@ -75,9 +137,11 @@ def clean(
for call_rs in call_rss: for call_rs in call_rss:
cleaned_message = cleaned_message.replace( cleaned_message = cleaned_message.replace(
f"<@{call_rs.user_id}>", f"<@{call_rs.user_id}>",
f"@**{call_rs.display_name}**" (
if message.channel.id == call_rs.channel_id f"@**{call_rs.display_name}**"
else f"@**{call_rs.profile.name}**", if message.channel.id == call_rs.channel_id
else f"@**{call_rs.profile.name}**"
),
) )
for user in message.mentions: for user in message.mentions:
+5 -3
View File
@@ -82,9 +82,11 @@ class HelpCommand(commands.HelpCommand):
[f" <{option.name}>" for option in command.options] [f" <{option.name}>" for option in command.options]
if isinstance(command, discord.SlashCommand) if isinstance(command, discord.SlashCommand)
else [ else [
f" [<{name}>]" (
if typing_utils.is_optional(info.annotation) f" [<{name}>]"
else f" <{name}>" if typing_utils.is_optional(info.annotation)
else f" <{name}>"
)
for name, info in command.params.items() for name, info in command.params.items()
if name not in ["self", "ctx"] if name not in ["self", "ctx"]
] ]
+1 -2
View File
@@ -7,8 +7,7 @@ from payphone.core import config
async def init() -> None: async def init() -> None:
"""Initialize the database and it's connections. """Initialize the database and it's connections."""
"""
await tortoise.Tortoise.init(config.TORTOISE_ORM, use_tz=True) await tortoise.Tortoise.init(config.TORTOISE_ORM, use_tz=True)