Skip to content

Commit eae1d66

Browse files
AmbratolmAmbratolm
authored andcommitted
Added & improved API routers
1 parent 243392e commit eae1d66

File tree

6 files changed

+223
-106
lines changed

6 files changed

+223
-106
lines changed

api/routers/actor_router.py

Lines changed: 0 additions & 57 deletions
This file was deleted.

api/routers/member_router.py

Lines changed: 46 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
from typing import cast
2-
3-
from discord import Guild, Member
1+
from discord import Member
42
from fastapi import APIRouter, HTTPException
3+
from odmantic import query
54

6-
from bot.cogs.board_cog import BoardCog
75
from bot.main import ActBot
86
from db.actor import Actor
7+
from utils.log import logger
8+
9+
log = logger(__name__)
910

1011

1112
# ----------------------------------------------------------------------------------------------------
@@ -15,40 +16,53 @@ class MemberRouter(APIRouter):
1516
def __init__(self, bot: ActBot, *args, **kwargs):
1617
super().__init__(prefix="/members", tags=["Members"], *args, **kwargs)
1718

18-
def member_dict(member: Member):
19-
return (
20-
{
21-
"id": member.id,
22-
"name": member.name,
23-
"display_name": member.display_name,
24-
"diplay_avatar_url": member.display_avatar.url,
25-
"display_icon_url": member.display_icon,
26-
"banner_url": member.banner.url if member.banner else None,
27-
"created_at": member.created_at,
28-
"joined_at": member.joined_at,
29-
}
30-
if member
31-
else {}
32-
)
19+
def member_dict(member: Member, actor: Actor):
20+
return {
21+
**actor.model_dump(),
22+
"id": member.id,
23+
"name": member.name,
24+
"display_name": member.display_name,
25+
"display_avatar_url": member.display_avatar.url,
26+
"display_icon_url": member.display_icon,
27+
"banner_url": member.banner.url if member.banner else None,
28+
"created_at": member.created_at,
29+
"joined_at": member.joined_at,
30+
}
3331

3432
# ----------------------------------------------------------------------------------------------------
3533

36-
@self.get("/{guild_id}/top", response_model=list[dict])
37-
async def get_top_members(guild_id: int, limit: int = 10):
34+
@self.get("/{guild_id}", response_model=list[dict])
35+
async def get_members(guild_id: int, limit: int = 10, top: bool = True):
3836
try:
3937
for guild in bot.guilds:
4038
if guild.id == guild_id:
41-
top_actors = cast(
42-
BoardCog, bot.get_cog(BoardCog.__cog_name__)
43-
).get_top_actors(guild, limit)
44-
45-
return [
46-
member_dict(
47-
guild.get_member(actor.id)
48-
or await guild.fetch_member(actor.id)
39+
db = bot.get_db(guild)
40+
actors = (
41+
db.find(
42+
Actor,
43+
sort=(
44+
query.desc(Actor.rank),
45+
query.desc(Actor.level),
46+
query.desc(Actor.xp),
47+
query.desc(Actor.gold),
48+
),
49+
limit=limit,
4950
)
50-
for actor in top_actors
51-
]
51+
if top
52+
else db.find(Actor, limit=limit)
53+
)
54+
members = []
55+
for actor in actors:
56+
member = None
57+
try:
58+
member = guild.get_member(
59+
actor.id
60+
) or await guild.fetch_member(actor.id)
61+
except:
62+
pass
63+
if member:
64+
members.append(member_dict(member, actor))
65+
return members
5266
raise HTTPException(
5367
status_code=404,
5468
detail=f"No guild with id '{guild_id}' found among the guilds the discord bot is member of.",
@@ -58,4 +72,5 @@ async def get_top_members(guild_id: int, limit: int = 10):
5872
detail="No guilds found. The discord bot is not member of any guild",
5973
)
6074
except Exception as e:
75+
log.exception(e)
6176
raise HTTPException(status_code=400, detail=str(e))

bot/cogs/ai_cog.py

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,7 @@
22
import tomllib
33
from datetime import UTC, datetime
44

5-
from discord import (
6-
DMChannel,
7-
GroupChannel,
8-
Guild,
9-
Interaction,
10-
Member,
11-
Message,
12-
TextChannel,
13-
Thread,
14-
User,
15-
app_commands,
16-
)
5+
from discord import Guild, Interaction, Member, Message, User, app_commands
176
from discord.abc import Messageable
187
from discord.ext import tasks
198
from discord.ext.commands import Cog

bot/cogs/console_cog.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ def __init__(self, bot: ActBot):
1616
# ----------------------------------------------------------------------------------------------------
1717
# * Sync
1818
# ----------------------------------------------------------------------------------------------------
19+
@app_commands.default_permissions(administrator=True)
1920
@app_commands.checks.has_permissions(administrator=True)
2021
@app_commands.command(description="Synchronize commands")
2122
async def sync(self, interaction: Interaction):

bot/cogs/purge_cog.py

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
# import re
2+
# from datetime import datetime, timedelta
3+
4+
# import discord
5+
# from discord import Member, app_commands
6+
# from discord.abc import Messageable, PrivateChannel
7+
# from discord.ext import commands
8+
9+
# from bot.ui import EmbedX
10+
11+
12+
# # ----------------------------------------------------------------------------------------------------
13+
# # * Purge Cog
14+
# # ----------------------------------------------------------------------------------------------------
15+
# class PurgeCog(commands.Cog):
16+
# def __init__(self, bot):
17+
# self.bot = bot
18+
19+
# @app_commands.command(
20+
# name="purge",
21+
# description="Delete messages based on count, time, or message range",
22+
# )
23+
# @app_commands.describe(
24+
# value="Count (e.g., 10), time (e.g., 5m/2h/1d), or message URL/ID",
25+
# second_value="Second message URL/ID for range deletion (optional)",
26+
# user="Only delete messages from this user (optional)",
27+
# )
28+
# @app_commands.checks.has_permissions(manage_messages=True)
29+
# async def purge(
30+
# self,
31+
# interaction: discord.Interaction,
32+
# value: str,
33+
# second_value: str | None = None,
34+
# user: Member | None = None,
35+
# ):
36+
# """ """
37+
# if (
38+
# not interaction.guild
39+
# or not interaction.channel
40+
# or not isinstance(interaction.channel, Messageable)
41+
# or isinstance(interaction.channel, PrivateChannel)
42+
# ):
43+
# await interaction.followup.send(
44+
# embed=EmbedX.warning("This command cannot be used in this context."),
45+
# ephemeral=True,
46+
# )
47+
# return
48+
49+
# await interaction.response.defer(ephemeral=True)
50+
# channel = interaction.channel
51+
52+
# # Check bot permissions
53+
# if not channel.permissions_for(interaction.guild.me).manage_messages:
54+
# await interaction.followup.send(
55+
# embed=EmbedX.warning("You don't have permission to manage messages."),
56+
# ephemeral=True,
57+
# )
58+
# return
59+
60+
# try:
61+
# # Case 1: Purge by count
62+
# if value.isdigit():
63+
# count = min(
64+
# int(value), 100
65+
# ) # Discord limit is 100 messages per bulk delete
66+
# messages = [
67+
# msg
68+
# async for msg in channel.history(limit=count + 1)
69+
# if not user or msg.author == user
70+
# ]
71+
# await channel.delete_messages(messages)
72+
# await interaction.followup.send(
73+
# embed=EmbedX.success(f"Deleted **{len(messages)}** messages."),
74+
# ephemeral=True,
75+
# )
76+
# return
77+
78+
# # Case 2: Purge by time
79+
# time_units = {"s": 1, "m": 60, "h": 3600, "d": 86400}
80+
# if value[-1] in time_units and value[:-1].isdigit():
81+
# time_amount = int(value[:-1])
82+
# time_unit = time_units[value[-1]]
83+
# time_delta = timedelta(seconds=time_amount * time_unit)
84+
# cutoff_time = datetime.utcnow() - time_delta
85+
86+
# messages = [
87+
# msg
88+
# async for msg in channel.history(limit=100)
89+
# if msg.created_at > cutoff_time and (not user or msg.author == user)
90+
# ]
91+
# await channel.delete_messages(messages)
92+
# await interaction.followup.send(
93+
# embed=EmbedX.warning(
94+
# f"Deleted **{len(messages)}** messages from last {value}."
95+
# ),
96+
# ephemeral=True,
97+
# )
98+
# return
99+
100+
# # Case 3 & 4: Purge by message or between messages
101+
# start_msg = await self.get_message_from_input(channel, value)
102+
# if not start_msg:
103+
# await interaction.followup.send(
104+
# embed=EmbedX.error("Invalid message ID or URL."), ephemeral=True
105+
# )
106+
# return
107+
108+
# if second_value: # Between two messages
109+
# end_msg = await self.get_message_from_input(channel, second_value)
110+
# if not end_msg:
111+
# await interaction.followup.send(
112+
# embed=EmbedX.error("Invalid second message ID or URL."),
113+
# ephemeral=True,
114+
# )
115+
# return
116+
117+
# # Ensure start_msg is older than end_msg
118+
# if start_msg.created_at > end_msg.created_at:
119+
# start_msg, end_msg = end_msg, start_msg
120+
121+
# messages = [
122+
# msg
123+
# async for msg in channel.history(limit=100, before=end_msg)
124+
# if msg.created_at >= start_msg.created_at
125+
# and (not user or msg.author == user)
126+
# ]
127+
# else: # Until one message
128+
# messages = [
129+
# msg
130+
# async for msg in channel.history(limit=100, before=start_msg)
131+
# if not user or msg.author == user
132+
# ]
133+
134+
# await channel.delete_messages(messages)
135+
# await interaction.followup.send(
136+
# embed=EmbedX.success(f"Deleted **{len(messages)}** messages"),
137+
# ephemeral=True,
138+
# )
139+
140+
# except discord.Forbidden:
141+
# await interaction.followup.send(
142+
# embed=EmbedX.error("You don't have permission to delete messages!"),
143+
# ephemeral=True,
144+
# )
145+
# except Exception as e:
146+
# await interaction.followup.send(embed=EmbedX.error(str(e)), ephemeral=True)
147+
148+
# @purge.error
149+
# async def purge_error(self, interaction: discord.Interaction, error):
150+
# if isinstance(error, app_commands.MissingPermissions):
151+
# await interaction.response.send_message(
152+
# embed=EmbedX.warning(
153+
# "You need Manage Messages permission to use this command!"
154+
# ),
155+
# ephemeral=True,
156+
# )
157+
158+
# # ----------------------------------------------------------------------------------------------------
159+
160+
# async def get_message_from_input(self, channel, input_str):
161+
# """Extract message ID from URL or plain ID."""
162+
# url_pattern = r"https://discord\.com/channels/\d+/\d+/(\d+)"
163+
# match = re.match(url_pattern, input_str)
164+
# if match:
165+
# message_id = int(match.group(1))
166+
# else:
167+
# try:
168+
# message_id = int(input_str)
169+
# except ValueError:
170+
# return None
171+
# try:
172+
# return await channel.fetch_message(message_id)
173+
# except discord.NotFound:
174+
# return None

bot/main.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -211,12 +211,7 @@ def create_db_ref(self, guild: Guild) -> DbRef:
211211

212212
def create_actor(self, member: Member | User) -> Actor:
213213
"""Create actor from given member."""
214-
return Actor(
215-
id=member.id,
216-
name=member.name,
217-
display_name=member.display_name,
218-
avatar_url=member.display_avatar.url if member.avatar else "",
219-
)
214+
return Actor(id=member.id, name=member.name, display_name=member.display_name)
220215

221216
# ----------------------------------------------------------------------------------------------------
222217

0 commit comments

Comments
 (0)