feat(bot): ✨ Add servers leaderboard.

This commit is contained in:
Nyeki.py
2024-10-19 00:39:33 -03:00
parent de65936073
commit 4e040ca8ad
6 changed files with 174 additions and 21 deletions
+82 -3
View File
@@ -1,7 +1,10 @@
import discord
from discord.ext import commands
from datetime import datetime, timezone
from tortoise import transactions
import discord
from discord import errors
from discord.ext import commands, tasks
from tortoise import transactions, functions, exceptions
from payphone import bot
from payphone.db import models, utils
@@ -12,6 +15,82 @@ class Admin(base.Cog):
def __init__(self, bot_instance: bot.Payphone):
self.bot = bot_instance
self.update_leaderboard.add_exception_type(exceptions.ConfigurationError)
self.update_leaderboard.start()
def cog_unload(self) -> None:
self.update_leaderboard.cancel()
@tasks.loop(minutes=15)
async def update_leaderboard(self) -> None:
"""Updates the leaderboard."""
calls = (
await models.Call.annotate(messages_count=functions.Count("messages"))
.filter(
started_at__month=datetime.now(timezone.utc).month,
started_at__year=datetime.now(timezone.utc).year,
messages_count__gte=25,
)
.prefetch_related(
"call_rss", "call_rss__channel", "call_rss__channel__server"
)
)
# ID to count
servers_count_map: dict[int, int] = {}
servers_map: dict[int, models.Server] = {
rs.channel.server_id: rs.channel.server
for call in calls
for rs in call.call_rss
}
for call in calls:
for rs in call.call_rss:
if rs.channel.server_id in servers_count_map:
servers_count_map[rs.channel.server.id] += 1
else:
servers_count_map[rs.channel.server_id] = 0
server_counts = list(servers_count_map.items())
server_counts.sort(key=lambda i: i[1], reverse=True)
for server_map in server_counts[:10]:
if servers_map[server_map[0]].name is None:
try:
servers_map[server_map[0]].name = (
await self.bot.fetch_guild(server_map[0])
).name
except errors.DiscordException:
pass
for i, server_map in enumerate(server_counts):
servers_map[server_map[0]].leaderboard_position = i + 1
servers_map[server_map[0]].leaderboard_calls_count = server_map[1]
await models.Server.bulk_update(
servers_map.values(),
["name", "leaderboard_position", "leaderboard_calls_count"],
500,
)
@commands.Cog.listener()
async def on_guild_update(
self, _before: discord.Guild, after: discord.Guild
) -> None:
"""Updates a server.
Args:
_before (discord.Guild): The server before it being updated.
after (discord.Guild): The server after it being updated.
"""
await models.Server.update_or_create({"name": after.name}, id=after.id)
@commands.group(invoke_without_command=True)
@commands.guild_only()
@commands.has_guild_permissions(manage_guild=True)