Skip to content

Commit 00e1a4a

Browse files
committed
add logging channel as optional item
1 parent 8d1119c commit 00e1a4a

File tree

9 files changed

+219
-11
lines changed

9 files changed

+219
-11
lines changed

alembic/env.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
# add db items to autogenerate the migrations
99
from config import load_config
1010
from database import connection
11-
from database.dto import users, kd_roles # noqa: F401
11+
from database.dto import users, kd_roles, server_settings # noqa: F401
1212

1313
# this is the Alembic Config object, which provides
1414
# access to the values within the .ini file in use.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
"""add settings table
2+
3+
Revision ID: b8035ea3f1d4
4+
Revises: 3c93bb5d292f
5+
Create Date: 2026-03-13 08:38:09.061353
6+
7+
"""
8+
from typing import Sequence, Union
9+
10+
from alembic import op
11+
import sqlalchemy as sa
12+
13+
14+
# revision identifiers, used by Alembic.
15+
revision: str = 'b8035ea3f1d4'
16+
down_revision: Union[str, Sequence[str], None] = '3c93bb5d292f'
17+
branch_labels: Union[str, Sequence[str], None] = None
18+
depends_on: Union[str, Sequence[str], None] = None
19+
20+
21+
def upgrade() -> None:
22+
"""Upgrade schema."""
23+
# ### commands auto generated by Alembic - please adjust! ###
24+
op.create_table('server_settings',
25+
sa.Column('server_id', sa.BigInteger(), nullable=False),
26+
sa.Column('log_channel_id', sa.BigInteger(), nullable=True),
27+
sa.Column('server_name', sa.String(), nullable=False),
28+
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
29+
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
30+
sa.PrimaryKeyConstraint('server_id')
31+
)
32+
# ### end Alembic commands ###
33+
34+
35+
def downgrade() -> None:
36+
"""Downgrade schema."""
37+
# ### commands auto generated by Alembic - please adjust! ###
38+
op.drop_table('server_settings')
39+
# ### end Alembic commands ###

bot.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from logger import setup_logger
1414

1515
from utils.kd_roles import get_all_kd_roles
16+
from utils.server_settings import add_guild, has_guild
1617
from utils.user_servers import fetch_user_servers
1718

1819
env_config = load_config()
@@ -35,8 +36,15 @@ async def setup_hook(self):
3536
await self.db.init_db()
3637
self.remove_command("help")
3738
await self.load_cogs()
38-
logger.info("bot started")
39+
logger.info("Adding all servers of the bot to the db")
3940
self.update_kdr.start()
41+
async with self.db.create_session() as session:
42+
async for guild in self.fetch_guilds():
43+
if not await has_guild(session, guild.id):
44+
await add_guild(session, guild, {})
45+
logger.info(f'Added guild "{guild.name}"')
46+
47+
logger.info("Bot started")
4048

4149
async def load_cogs(self):
4250
for file in os.listdir(os.path.dirname(__file__) + "/cogs"):
@@ -47,7 +55,7 @@ async def load_cogs(self):
4755

4856
@tasks.loop(hours=12)
4957
async def update_kdr(self):
50-
logger.info("updating KDR roles...")
58+
logger.info("Updating KDR roles...")
5159
from utils.role_management import RoleManagement # against circular import
5260

5361
async with self.db.create_session() as session:
@@ -79,6 +87,14 @@ async def update_kdr(self):
7987
bot = KDRBot(command_prefix="!", intents=intents)
8088

8189

90+
@bot.event
91+
async def on_guild_join(guild: discord.Guild):
92+
async with bot.db.create_session() as session:
93+
if not await has_guild(session, guild.id):
94+
await add_guild(session, guild, {})
95+
logger.info(f'Added guild "{guild.name}"')
96+
97+
8298
@bot.event
8399
async def on_command_error(ctx, error):
84100
"""dont give a error if a command doesn't exist"""

cogs/admin.py

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,21 @@
11
"""User management"""
22

33
import logging
4-
import os
5-
import sys
6-
74
import discord
85
from discord import Role, app_commands
96
from discord.ext import commands
10-
from sqlalchemy import select, func, and_
7+
from sqlalchemy import insert, select, func, and_
118
from sqlalchemy.exc import IntegrityError
129

1310
from bot import KDRBot
1411
from database.dto.kd_roles import KDRole
12+
from database.dto.server_settings import ServerSetting
1513
from database.dto.users import User
1614
from database.error_handling import is_unique_violation
1715
from utils.kd_roles import get_kd_roles
1816
from utils.register import register
1917
from utils.role_management import RoleManagement
18+
from utils.server_settings import add_guild, update_guild
2019

2120

2221
class RegisterModal(discord.ui.Modal, title="Register your EA account"):
@@ -222,6 +221,32 @@ async def generate_register(self, interaction: discord.Interaction) -> None:
222221
embed=embed, view=RegisterView(self.bot)
223222
)
224223

224+
logging_group = app_commands.Group(
225+
name="log", description="Manage the logging", parent=group
226+
)
227+
228+
@logging_group.command(
229+
name="channel",
230+
description="Set the channel to log new registration attempts to",
231+
)
232+
@app_commands.guild_only()
233+
@app_commands.default_permissions(administrator=True)
234+
@app_commands.checks.has_permissions(administrator=True)
235+
async def set_log_channel(
236+
self, interaction: discord.Interaction, channel: discord.TextChannel
237+
) -> None:
238+
"""Set the channel to log new registration attempts to"""
239+
await interaction.response.defer()
240+
if interaction.guild is None:
241+
return # is already set to guild_only
242+
async with self.bot.db.create_session() as session:
243+
await update_guild(
244+
session, interaction.guild, {"log_channel_id": channel.id}
245+
)
246+
await interaction.followup.send(
247+
f'Set the logging channel to "{channel.name}"', ephemeral=True
248+
)
249+
225250

226251
async def setup(bot: KDRBot) -> None:
227252
"""Setup the cog within discord.py lib"""

database/dto/server_settings.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import datetime
2+
from typing import Optional
3+
from sqlalchemy import BigInteger, DateTime, func
4+
from sqlalchemy.orm import Mapped, mapped_column
5+
from database.connection import Base
6+
7+
8+
class ServerSetting(Base):
9+
__tablename__ = "server_settings"
10+
server_id: Mapped[int] = mapped_column(BigInteger, primary_key=True)
11+
log_channel_id: Mapped[Optional[int]] = mapped_column(BigInteger)
12+
server_name: Mapped[str]
13+
created_at: Mapped[datetime.datetime] = mapped_column(
14+
DateTime(timezone=True), server_default=func.now()
15+
)
16+
updated_at: Mapped[datetime.datetime] = mapped_column(
17+
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
18+
)

poetry.lock

Lines changed: 18 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ dependencies = [
1414
"aiosqlite (>=0.22.1,<0.23.0)",
1515
"asyncpg (>=0.31.0,<0.32.0)",
1616
"pydantic (>=2.12.5,<3.0.0)",
17-
"environs (>=14.6.0,<15.0.0)"
17+
"environs (>=14.6.0,<15.0.0)",
18+
"psycopg2 (>=2.9.11,<3.0.0)"
1819
]
1920

2021

utils/register.py

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,34 @@
55
from database.error_handling import is_unique_violation
66
from utils.kd_roles import get_kd_roles
77
from utils.role_management import RoleManagement
8+
from utils.server_settings import send_log
89

910

1011
async def register(bot: KDRBot, interaction: discord.Interaction, username: str):
1112
async with bot.db.create_session() as session:
1213
players = await bot.gametools_api.find_player(interaction, username)
1314
if len(players) <= 0:
14-
await interaction.followup.send("User not found", ephemeral=True)
15+
msg = "User not found"
16+
await interaction.followup.send(msg, ephemeral=True)
17+
await send_log(
18+
bot,
19+
session,
20+
interaction.guild_id,
21+
f'{interaction.user.mention} just tried to register with EA ID: "{username}", {msg}',
22+
)
1523
return
1624
found_player = players[0]
1725

1826
stats = await bot.gametools_api.get_stats(found_player)
1927
if len(players) <= 0:
20-
await interaction.followup.send("No stats found for user", ephemeral=True)
28+
msg = "No stats found for user"
29+
await interaction.followup.send(msg, ephemeral=True)
30+
await send_log(
31+
bot,
32+
session,
33+
interaction.guild_id,
34+
f'{interaction.user.mention} just tried to register with EA ID: "{username}", {msg}',
35+
)
2136
return
2237

2338
stat = stats[0]
@@ -30,12 +45,25 @@ async def register(bot: KDRBot, interaction: discord.Interaction, username: str)
3045
try:
3146
session.add(found_player)
3247
await session.commit()
48+
await send_log(
49+
bot,
50+
session,
51+
interaction.guild_id,
52+
f'{interaction.user.mention} just registered with EA ID: "{username}"',
53+
)
3354
except IntegrityError as ex:
55+
await session.rollback()
3456
if is_unique_violation(ex):
3557
await interaction.followup.send(
3658
"You are already registered within this discord!",
3759
ephemeral=True,
3860
)
61+
await send_log(
62+
bot,
63+
session,
64+
interaction.guild_id,
65+
f'{interaction.user.mention} just tried to register with EA ID: "{username}", but is already registered',
66+
)
3967
return
4068

4169
await interaction.followup.send("Registered", ephemeral=True)

utils/server_settings.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
from typing import Optional
2+
3+
import discord
4+
from sqlalchemy import select, update
5+
from sqlalchemy.dialects.postgresql import insert
6+
from sqlalchemy.exc import IntegrityError
7+
from sqlalchemy.ext.asyncio import AsyncSession
8+
from database.dto.server_settings import ServerSetting
9+
10+
11+
async def add_guild(session: AsyncSession, guild: discord.Guild, changes: dict) -> None:
12+
data = dict(server_id=guild.id, server_name=guild.name)
13+
data.update(changes)
14+
stmt = insert(ServerSetting).values(data)
15+
do_update_stmt = stmt.on_conflict_do_update(
16+
index_elements=[ServerSetting.server_id],
17+
set_=dict((k, v) for (k, v) in data.items() if k != "created_at"),
18+
)
19+
20+
try:
21+
await session.execute(do_update_stmt)
22+
await session.commit()
23+
except IntegrityError:
24+
pass
25+
26+
27+
async def update_guild(session: AsyncSession, guild: discord.Guild, changes: dict):
28+
if not await has_guild(session, guild.id):
29+
await add_guild(session, guild, changes)
30+
return
31+
32+
stmt = (
33+
update(ServerSetting).where(ServerSetting.server_id == guild.id).values(changes)
34+
)
35+
await session.execute(stmt)
36+
await session.commit()
37+
38+
39+
async def get_guild(session: AsyncSession, server_id: int) -> Optional[ServerSetting]:
40+
stmt = select(ServerSetting).filter(ServerSetting.server_id == server_id).limit(1)
41+
result = await session.execute(stmt)
42+
return result.scalar_one_or_none()
43+
44+
45+
async def has_guild(session: AsyncSession, server_id: int) -> bool | None:
46+
exists_criteria = (
47+
select(ServerSetting.server_id)
48+
.filter(ServerSetting.server_id == server_id)
49+
.exists()
50+
)
51+
stmt = select(exists_criteria)
52+
return await session.scalar(stmt)
53+
54+
55+
async def send_log(bot, session: AsyncSession, server_id: int | None, message: str):
56+
if server_id is None:
57+
return
58+
settings = await get_guild(session, server_id)
59+
if settings is None or settings.log_channel_id is None:
60+
return
61+
62+
channel = bot.get_channel(settings.log_channel_id)
63+
if isinstance(channel, discord.TextChannel):
64+
await channel.send(message)

0 commit comments

Comments
 (0)