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(
color=constants.EMBED_COLOR,
description=formatting.trim(last_content.content)
if last_content.was_propagated or is_this_channel
else "*This message was censored.*",
description=(
formatting.trim(last_content.content)
if last_content.was_propagated or is_this_channel
else "*This message was censored.*"
),
author=discord.EmbedAuthor(
name=f"Replied to {author_name}",
icon_url=author_avatar_url,
+90 -17
View File
@@ -1,3 +1,5 @@
from typing import Awaitable
from datetime import datetime, timezone, timedelta
import sys
@@ -13,7 +15,7 @@ from payphone import bot
from payphone.db import models, utils
from payphone.cogs import base
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):
@@ -291,29 +293,100 @@ class Mods(base.Cog):
@commands.command()
@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.
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 = [
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)}",
f"Messages: {await models.Message.all().count()}",
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()}",
f"Bans: {await models.Ban.all().count()}",
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()}",
f"Profiles: {await models.Profile.all().count()}",
f"Servers: {await models.Server.all().count()}",
f"Shards: {self.bot.shard_count}",
f"Current Shard: {ctx.guild.shard_id + 1}",
(
"On-call Channels",
lambda: self.bot.redis.scard(constants.CHANNELS_ONCALL_SET),
),
(
"Searching Channels",
lambda: self.bot.redis.scard(constants.CHANNELS_SEARCH_QUEUE),
),
(
"Messages",
lambda: models.Message.all().count(),
),
(
"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:
+10 -6
View File
@@ -28,15 +28,19 @@ class BanNotificationEmbed(discord.Embed):
),
discord.EmbedField(
name="Expires At",
value=f"<t:{int(ban.expires_at.timestamp())}:F> (<t:{int(ban.expires_at.timestamp())}:R>)"
if ban.expires_at
else "*Does not expire.*",
value=(
f"<t:{int(ban.expires_at.timestamp())}:F> (<t:{int(ban.expires_at.timestamp())}:R>)"
if ban.expires_at
else "*Does not expire.*"
),
),
discord.EmbedField(
name="Appeal",
value="*You haven't appealed this ban.*"
if ban.appeal is None
else ban.appeal,
value=(
"*You haven't appealed this ban.*"
if ban.appeal is None
else ban.appeal
),
),
],
author=bot.embed_author,
+2 -2
View File
@@ -186,7 +186,7 @@ class ReportView(discord.ui.View):
await interaction.response.edit_message(
content="✅ You're up to date! No reports left to check.",
embed=None,
view=None
view=None,
)
return
@@ -218,7 +218,7 @@ class ReportView(discord.ui.View):
await interaction.response.edit_message(
content="✅ You're up to date! No reports left to check.",
embed=None,
view=None
view=None,
)
return
+5 -3
View File
@@ -175,9 +175,11 @@ class Users(base.Cog):
logs += f"- `{call_id}`: "
participant_names = ", ".join(
call_rs.display_name
if call_rs.channel_id != data["user_rs"].channel_id
else call_rs.profile.name
(
call_rs.display_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"]]
)
+3 -3
View File
@@ -246,16 +246,16 @@ def moderate(message: str) -> str:
match = next(PATTERN.finditer(message), 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)
if match is not None:
return message[match.start():match.end()]
return message[match.start() : match.end()]
match = next(INVITES_PATTERN.finditer(message), None)
if match is not None:
return message[match.start():match.end()]
return message[match.start() : match.end()]
return None
+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]) + "```"
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(
message: discord.Message, call_rss: list[models.CallUserChannelRelationship]
) -> str:
@@ -75,9 +137,11 @@ def clean(
for call_rs in call_rss:
cleaned_message = cleaned_message.replace(
f"<@{call_rs.user_id}>",
f"@**{call_rs.display_name}**"
if message.channel.id == call_rs.channel_id
else f"@**{call_rs.profile.name}**",
(
f"@**{call_rs.display_name}**"
if message.channel.id == call_rs.channel_id
else f"@**{call_rs.profile.name}**"
),
)
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]
if isinstance(command, discord.SlashCommand)
else [
f" [<{name}>]"
if typing_utils.is_optional(info.annotation)
else f" <{name}>"
(
f" [<{name}>]"
if typing_utils.is_optional(info.annotation)
else f" <{name}>"
)
for name, info in command.params.items()
if name not in ["self", "ctx"]
]
+1 -2
View File
@@ -7,8 +7,7 @@ from payphone.core import config
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)