Compare commits

...
Author SHA1 Message Date
imcompiling 1ffb7fa9a7 Correct database ignore.
build_develop / build (push) Successful in 18s
build_latest / build (push) Successful in 18s
build_release / build (push) Successful in 19s
2025-03-19 09:51:38 -04:00
imcompiling 2566bee0ce Use home dir.
build_develop / build (push) Successful in 36s
2025-03-19 09:37:32 -04:00
imcompiling 3d113a06d4 Update workflows.
build_develop / build (push) Successful in 35s
2025-03-19 09:35:21 -04:00
imcompiling 2e3b8c86da Add more to dockerignore. 2025-03-19 09:30:44 -04:00
imcompiling 058e3aefa1 Update how agon is run. 2025-03-19 09:28:30 -04:00
imcompiling 7a4ba3a5af Update all imports with new file structure. 2025-03-19 09:22:29 -04:00
imcompiling 2f5f25ea75 Remove unneede file. 2025-03-19 09:17:43 -04:00
imcompiling fd476ce512 Move files from utilities to top level of module. 2025-03-19 09:17:07 -04:00
imcompiling 9588cdc8a0 Rename main.py to app.py, add init and main dunder files. 2025-03-19 09:11:02 -04:00
imcompiling 17769022bc Move all files into agon module. 2025-03-19 09:07:39 -04:00
imcompiling a46dc0388c Delete sql file. it is unneeded now. 2025-03-19 09:07:14 -04:00
imcompiling 553f79425f Delete database/pyproject.toml
build_develop / build (push) Successful in 36s
2025-03-19 08:49:17 -04:00
imcompiling 72cd6e9fd1 Merge pull request 'Update ghcr.io/astral-sh/uv Docker tag to v0.6.6' (#87) from renovate/ghcr.io-astral-sh-uv-0.x into main
build_develop / build (push) Successful in 56s
Reviewed-on: #87
Reviewed-by: imcompiling <[email protected]>
2025-03-16 11:09:44 -04:00
renovate-bot f63984e25a Update ghcr.io/astral-sh/uv Docker tag to v0.6.6 2025-03-16 04:01:28 +00:00
imcompiling 48a91dca3d Merge branch '41-editting-commands'
build_develop / build (push) Successful in 35s
build_release / build (push) Successful in 22s
2025-03-14 17:22:03 -04:00
imcompiling 5eb637a3a8 Indent so that a command can properly use session.
Remove commented out code. Also add work to an issue.
2025-03-14 17:20:50 -04:00
imcompiling f722eb1a83 Add to get's return messages. 2025-03-14 17:05:39 -04:00
imcompiling 7759bbc648 Add to set's return messages. 2025-03-14 17:04:20 -04:00
imcompiling 65de7baeda Added some log statements to provide helpful information. 2025-03-14 16:57:38 -04:00
imcompiling e243404480 Forgot to specify that is a description. 2025-03-14 16:53:15 -04:00
imcompiling f735e6d846 Merge branch '70-sqlmodel'
build_develop / build (push) Successful in 34s
build_release / build (push) Successful in 22s
2025-03-14 16:43:28 -04:00
imcompiling 9fbaf7bcf6 Merge branch 'main' of https://gitea.cheezers.org/imcompiling/agon
build_develop / build (push) Has been cancelled
2025-03-14 16:42:48 -04:00
imcompiling 1959e11e5c Merge branch '70-sqlmodel' into 41-editting-commands 2025-03-14 16:42:33 -04:00
imcompiling c25d354fc0 Correct some parameter usage, handle errors if searches return nothing. 2025-03-14 16:09:52 -04:00
imcompiling e5d90a71d9 Correct parameter usage. 2025-03-14 16:02:18 -04:00
imcompiling 785a4eff46 Was saving the message id to the wrong spot. 2025-03-13 09:21:10 -04:00
imcompiling 627112b114 Use correct message id reference. 2025-03-13 09:21:09 -04:00
imcompiling 9b3bd9d02c Use correct variable for guild name. 2025-03-13 09:21:09 -04:00
imcompiling 2c56c614f3 Typo on col usage. 2025-03-13 09:21:09 -04:00
imcompiling 3ccaa7004e Had col around the wrong variables. 2025-03-13 09:21:08 -04:00
imcompiling 289113661f Use walrus operator when assigning and checking for None. 2025-03-13 09:21:08 -04:00
imcompiling 74ce22dd26 Was saving the message id to the wrong spot. 2025-03-13 00:39:47 -04:00
imcompiling 170ce1cbfb Use correct message id reference. 2025-03-12 21:30:56 -04:00
imcompiling e1b761e848 Use correct variable for guild name. 2025-03-12 21:29:01 -04:00
imcompiling 68592a7df8 Typo on col usage. 2025-03-12 21:27:29 -04:00
imcompiling b28938f66a Had col around the wrong variables. 2025-03-12 21:27:12 -04:00
imcompiling 3abbff13d5 Use walrus operator when assigning and checking for None. 2025-03-12 09:50:58 -04:00
imcompiling f52b2fe49f Merge pull request 'Update ghcr.io/astral-sh/uv Docker tag to v0.6.5' (#81) from renovate/ghcr.io-astral-sh-uv-0.x into main
build_develop / build (push) Successful in 48s
Reviewed-on: #81
Reviewed-by: imcompiling <[email protected]>
2025-03-10 08:40:41 -04:00
renovate-bot 24a9fa998a Update ghcr.io/astral-sh/uv Docker tag to v0.6.5 2025-03-09 05:01:04 +00:00
imcompiling 63db4c1dd2 Merge pull request 'Update ghcr.io/astral-sh/uv Docker tag to v0.6.3' (#79) from renovate/ghcr.io-astral-sh-uv-0.x into main
build_develop / build (push) Successful in 51s
Reviewed-on: #79
Reviewed-by: imcompiling <[email protected]>
2025-03-03 23:03:42 -05:00
renovate-bot 8604ba2547 Update ghcr.io/astral-sh/uv Docker tag to v0.6.3 2025-03-02 05:01:27 +00:00
41 changed files with 189 additions and 239 deletions
+3
View File
@@ -1,2 +1,5 @@
.*
Dockerfile
LICENSE
README.md
renovate.json
+10 -4
View File
@@ -2,14 +2,18 @@ name: build_develop
on:
push:
branches: [main]
branches:
- "*"
- "!main"
paths-ignore:
- "README.md"
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Install Docker
@@ -20,7 +24,9 @@ jobs:
registry: gitea.cheezers.org
username: imcompiling
password: ${{ secrets.PASSWORD }}
- name: set env
run: echo "GIT_BRANCH=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> $GITHUB_ENV
- name: Build Docker Image
run: docker build -t gitea.cheezers.org/imcompiling/agon:develop .
run: docker build -t gitea.cheezers.org/imcompiling/agon:${{env.GIT_BRANCH}} .
- name: Push Docker Image
run: docker push gitea.cheezers.org/imcompiling/agon:develop
run: docker push gitea.cheezers.org/imcompiling/agon:${{env.GIT_BRANCH}}
+28
View File
@@ -0,0 +1,28 @@
name: build_latest
on:
push:
branches: [main]
paths-ignore:
- "README.md"
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Install Docker
uses: https://github.com/papodaca/install-docker-action@v1
- name: Log into container registry
uses: docker/login-action@v3
with:
registry: gitea.cheezers.org
username: imcompiling
password: ${{ secrets.PASSWORD }}
- name: Build Docker Image
run: docker build -t gitea.cheezers.org/imcompiling/agon:latest .
- name: Push Docker Image
run: docker push gitea.cheezers.org/imcompiling/agon:latest
+1 -3
View File
@@ -23,8 +23,6 @@ jobs:
- name: Set env
run: echo "GIT_TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
- name: Build Docker Images
run: docker build -t gitea.cheezers.org/imcompiling/agon:latest -t gitea.cheezers.org/imcompiling/agon:${{env.GIT_TAG}} .
- name: Push Latest Image
run: docker push gitea.cheezers.org/imcompiling/agon:latest
run: docker build -t gitea.cheezers.org/imcompiling/agon:${{env.GIT_TAG}} .
- name: Push Tagged Image
run: docker push gitea.cheezers.org/imcompiling/agon:${{env.GIT_TAG}}
+1 -1
View File
@@ -135,4 +135,4 @@ deleted_backups/
highscores_data/
TODO.txt
sql_tester.py
database.db
/database
+2 -2
View File
@@ -8,8 +8,8 @@
"name": "Python: Module",
"type": "debugpy",
"request": "launch",
"module": "main",
"module": "agon",
"justMyCode": true
}
]
}
}
+2 -2
View File
@@ -10,8 +10,8 @@
"ondelete"
],
"python.analysis.diagnosticSeverityOverrides": {
"reportOptionalMemberAccess": false,
"reportOptionalMemberAccess": "warning",
"reportArgumentType": "information",
"reportAttributeAccessIssue": "warning"
}
}
}
+4 -4
View File
@@ -1,15 +1,15 @@
FROM python:3.12.3-slim
# install uv
COPY --from=ghcr.io/astral-sh/uv:0.6.2 /uv /uvx /bin/
COPY --from=ghcr.io/astral-sh/uv:0.6.6 /uv /uvx /bin/
RUN apt-get update && apt-get -y upgrade && apt-get -y install sqlite3
# Copy project to image
ADD . /agon
ADD . /home
# Sync the project into a new environment, using the frozen lockfile
WORKDIR /agon
WORKDIR /home
RUN uv sync --frozen --no-dev
CMD ["uv", "run", "./main.py"]
CMD ["uv", "run", "--frozen", "--no-dev", "-m", "agon"]
+1
View File
@@ -0,0 +1 @@
"""Empty init file for off_cooldown_bot module."""
+14
View File
@@ -0,0 +1,14 @@
"""Starts the app for agon."""
import logging
from .app import run
nextcord_logger = logging.getLogger("nextcord")
nextcord_logger.setLevel(logging.DEBUG)
nextcord_handler = logging.FileHandler(filename="nextcord.log", encoding="utf-8", mode="w")
nextcord_handler.setFormatter(logging.Formatter("%(asctime)s:%(levelname)s:%(name)s: %(message)s"))
nextcord_logger.addHandler(nextcord_handler)
if __name__ == "__main__":
run()
+6 -17
View File
@@ -1,23 +1,16 @@
"""Main file for Agon bot."""
import logging
import os
import pathlib
import sys
import nextcord
from nextcord.ext import commands
from utilities import config
from utilities.logger import agon_logger
nextcord_logger = logging.getLogger("nextcord")
nextcord_logger.setLevel(logging.DEBUG)
nextcord_handler = logging.FileHandler(filename="nextcord.log", encoding="utf-8", mode="w")
nextcord_handler.setFormatter(logging.Formatter("%(asctime)s:%(levelname)s:%(name)s: %(message)s"))
nextcord_logger.addHandler(nextcord_handler)
from . import config
from .logger import agon_logger
def main() -> None:
def run() -> None:
"""Main function for bot."""
min_python_version = (3, 12)
if sys.version_info < min_python_version:
@@ -34,8 +27,8 @@ def main() -> None:
)
# Get the modules of all cogs whose directory structure is ./cogs/<module_name>
for folder in os.listdir("cogs"):
bot.load_extension(f"cogs.{folder}")
for folder in pathlib.Path("./agon/cogs").iterdir():
bot.load_extension(f"agon.cogs.{folder.name}")
@bot.listen()
async def on_ready() -> None:
@@ -47,7 +40,3 @@ def main() -> None:
# Run Discord bot
bot.run(config.DISCORD_TOKEN)
if __name__ == "__main__":
main()
@@ -2,15 +2,15 @@
from nextcord.ext import commands
from cogs.commands.create import CreateCog
from cogs.commands.delete import DeleteCog
from cogs.commands.get import GetCog
from cogs.commands.help import HelpCog
from cogs.commands.refresh import RefreshCog
from cogs.commands.set import SetCog
from cogs.commands.submission import SubmissionCog
from cogs.commands.update import UpdateCog
from cogs.commands.view import ViewCog
from agon.cogs.commands.create import CreateCog
from agon.cogs.commands.delete import DeleteCog
from agon.cogs.commands.get import GetCog
from agon.cogs.commands.help import HelpCog
from agon.cogs.commands.refresh import RefreshCog
from agon.cogs.commands.set import SetCog
from agon.cogs.commands.submission import SubmissionCog
from agon.cogs.commands.update import UpdateCog
from agon.cogs.commands.view import ViewCog
# This function will be called when this extension is loaded.
@@ -6,9 +6,9 @@ from sqlalchemy import exc, select
from sqlalchemy.orm import Session
from sqlmodel import col
from database.db import engine
from database.models import Category, CategoryGroup
from utilities.utils import MAX_LINE_LENGTH, autofill_groups, send_highscore_message
from agon.database.db import engine
from agon.database.models import Category, CategoryGroup
from agon.utils import MAX_LINE_LENGTH, autofill_groups, send_highscore_message
class CreateCog(commands.Cog, name="Create Cog"):
@@ -6,9 +6,9 @@ from sqlalchemy import distinct, select
from sqlalchemy.orm import Session
from sqlmodel import col
from database.db import engine
from database.models import Category, CategoryGroup, Score
from utilities.utils import (
from agon.database.db import engine
from agon.database.models import Category, CategoryGroup, Score
from agon.utils import (
autofill_categories,
autofill_groups,
autofill_users_in_group_category,
@@ -4,9 +4,9 @@ import nextcord
from nextcord.ext import commands
from sqlmodel import Session, col, select
from database.db import engine
from database.models import Category, CategoryGroup
from utilities.utils import autofill_categories, autofill_groups
from agon.database.db import engine
from agon.database.models import Category, CategoryGroup
from agon.utils import autofill_categories, autofill_groups
class GetCog(commands.Cog, name="Get command."):
@@ -50,7 +50,7 @@ class GetCog(commands.Cog, name="Get command."):
return
await interaction.response.send_message(
f"{category.name} is sorted in {'ascending' if category.is_ascending else 'descending'} order.",
f"**{category.name}** is sorted in **{'ascending' if category.is_ascending else 'descending'}** order.",
ephemeral=True,
)
@@ -109,7 +109,9 @@ class GetCog(commands.Cog, name="Get command."):
await interaction.response.send_message("Group or Category was not found.", ephemeral=True)
return
await interaction.response.send_message(f"{category.name} has a size of {category.size}.", ephemeral=True)
await interaction.response.send_message(
f"**{category.name}** has a size of **{category.size}**.", ephemeral=True
)
@get.subcommand(description="Commands for getting group information.")
async def group(self, interaction: nextcord.Interaction) -> None:
@@ -136,7 +138,7 @@ class GetCog(commands.Cog, name="Get command."):
return
await interaction.response.send_message(
f"{group.name} has a pad length of {group.pad_length}.", ephemeral=True
f"**{group.name}** has a pad length of **{group.pad_length}**.", ephemeral=True
)
@group.subcommand(description="Get the username length of a group.")
@@ -162,7 +164,7 @@ class GetCog(commands.Cog, name="Get command."):
return
await interaction.response.send_message(
f"{group.name} has a username length of {group.username_length}.", ephemeral=True
f"**{group.name}** has a username length of **{group.username_length}**.", ephemeral=True
)
@is_ascending.on_autocomplete("category_id")
@@ -6,9 +6,9 @@ from sqlalchemy import select
from sqlalchemy.orm import Session
from sqlmodel import col
from database.db import engine
from database.models import CategoryGroup
from utilities.utils import autofill_groups, send_highscore_message
from agon.database.db import engine
from agon.database.models import CategoryGroup
from agon.utils import autofill_groups, send_highscore_message
class RefreshCog(commands.Cog, name="Refresh Cog"):
@@ -6,10 +6,10 @@ from sqlalchemy import select
from sqlalchemy.orm import Session
from sqlmodel import col
from database.db import engine
from database.models import Category, CategoryGroup, Guild
from utilities.logger import agon_logger
from utilities.utils import MAX_LINE_LENGTH, autofill_categories, autofill_groups, send_highscore_message
from agon.database.db import engine
from agon.database.models import Category, CategoryGroup, Guild
from agon.logger import agon_logger
from agon.utils import MAX_LINE_LENGTH, autofill_categories, autofill_groups, send_highscore_message
class SetCog(commands.Cog, name="Set command."):
@@ -22,7 +22,7 @@ class SetCog(commands.Cog, name="Set command."):
async def set(self, interaction: nextcord.Interaction) -> None:
"""Parent slash command for setting settings. Never called."""
@set.subcommand("Commands for editing a category.")
@set.subcommand(description="Commands for editing a category.")
async def category(self, interaction: nextcord.Interaction) -> None:
"""Parent slash subcommand for setting category settings. Never called."""
@@ -54,7 +54,6 @@ class SetCog(commands.Cog, name="Set command."):
await interaction.response.send_message("Category or Group was not found.", ephemeral=True)
return
category.size = size
# session.add(category) test if this is needed. SQLAlchemy can do the update without adding.
session.commit()
# Use the relationship to get group category is in.
@@ -67,7 +66,9 @@ class SetCog(commands.Cog, name="Set command."):
return
await send_highscore_message(session, interaction.guild, group)
await interaction.response.send_message(f"{category.name} size has been updated to {size}.", ephemeral=True)
await interaction.response.send_message(
f"**{category.name}** size has been updated to **{size}**.", ephemeral=True
)
@category.subcommand(description="Update the is_ascending value for a category.")
async def is_ascending(
@@ -99,7 +100,6 @@ class SetCog(commands.Cog, name="Set command."):
await interaction.response.send_message("Category or Group was not found.", ephemeral=True)
return
category.is_ascending = ascending
# session.add(category) test if this is needed. SQLAlchemy can do the update without adding.
session.commit()
# Use the relationship to get group category is in.
@@ -113,7 +113,7 @@ class SetCog(commands.Cog, name="Set command."):
await send_highscore_message(session, interaction.guild, group)
await interaction.response.send_message(
f"{category.name} is_ascending has been updated to {ascending}.", ephemeral=True
f"**{category.name}** is_ascending has been updated to **{ascending}**.", ephemeral=True
)
@category.subcommand(description="Update the is_validated value for a category.")
@@ -146,12 +146,11 @@ class SetCog(commands.Cog, name="Set command."):
await interaction.response.send_message("Category or Group was not found.", ephemeral=True)
return
category.is_validated = validated
# session.add(category) test if this is needed. SQLAlchemy can do the update without adding.
session.commit()
await interaction.response.send_message(
f"{category.name} is_validated has been updated to {validated}.", ephemeral=True
)
await interaction.response.send_message(
f"**{category.name}** is_validated has been updated to **{validated}**.", ephemeral=True
)
@category.subcommand(name="name", description="Change the name of a category.")
async def category_name(
@@ -182,7 +181,6 @@ class SetCog(commands.Cog, name="Set command."):
return
old_name = category.name
category.name = name
# session.add(category) test if this is needed. SQLAlchemy can do the update without adding.
session.commit()
# Use the relationship to get group category is in.
@@ -195,7 +193,9 @@ class SetCog(commands.Cog, name="Set command."):
return
await send_highscore_message(session, interaction.guild, group)
await interaction.response.send_message(f"{old_name} has been updated to {category.name}.", ephemeral=True)
await interaction.response.send_message(
f"**{old_name}** has been updated to **{category.name}**.", ephemeral=True
)
@set.subcommand(description="Commands for editing a group.")
async def group(self, interaction: nextcord.Interaction) -> None:
@@ -228,7 +228,7 @@ class SetCog(commands.Cog, name="Set command."):
session.commit()
await send_highscore_message(session, interaction.guild, group)
await interaction.response.send_message(f"{old_name} has been updated to {group.name}.", ephemeral=True)
await interaction.response.send_message(f"**{old_name}** has been updated to **{group.name}**.", ephemeral=True)
@group.subcommand(description="Registers the channel for a Group's messages.")
async def output_channel(
@@ -259,9 +259,14 @@ class SetCog(commands.Cog, name="Set command."):
.where(col(CategoryGroup.guild_id) == interaction.guild_id)
.where(col(CategoryGroup.id) == int(group_id))
)
group = session.scalar(stmt)
group.ChannelId = channel_id
if (group := session.scalar(stmt)) is None:
await interaction.response.send_message("Group or Category was not found.", ephemeral=True)
return
group.channel_id = channel_id
session.commit()
# TODO(imcompiling): delete the message and call send_highscore_message to send a new one. Bug needs fixed
# first.
# 082
await interaction.send(f"Registered <#{channel_id}>.", ephemeral=True)
@group.subcommand(
@@ -296,10 +301,11 @@ class SetCog(commands.Cog, name="Set command."):
if (group := session.scalar(stmt)) is None:
await interaction.response.send_message("Group was not found.", ephemeral=True)
return
group.PadLength = length
group.pad_length = length
session.commit()
await interaction.response.send_message(
f"Category pad length set to {length} for {group.name}", ephemeral=True
f"Category pad length set to **{length}** for **{group.name}**.", ephemeral=True
)
await send_highscore_message(session, interaction.guild, group)
@@ -328,7 +334,9 @@ class SetCog(commands.Cog, name="Set command."):
with Session(engine) as session:
stmt = select(Guild).where(col(Guild.id) == interaction.guild_id)
guild = session.scalar(stmt)
if (guild := session.scalar(stmt)) is None:
await interaction.response.send_message("Guild was not found.", ephemeral=True)
return
guild.submission_channel = channel_id
session.commit()
await interaction.send(f"Registered <#{channel_id}>.", ephemeral=True)
@@ -358,10 +366,15 @@ class SetCog(commands.Cog, name="Set command."):
.where(col(CategoryGroup.guild_id) == interaction.guild_id)
.where(col(CategoryGroup.id) == int(group_id))
)
group = session.scalar(stmt)
group.UsernameLength = length
if (group := session.scalar(stmt)) is None:
await interaction.response.send_message("Group or Category was not found.", ephemeral=True)
return
group.username_length = length
session.commit()
await interaction.response.send_message(f"Username length set to {length}.", ephemeral=True)
await interaction.response.send_message(
f"Username length for **{group.name}** set to **{length}**.", ephemeral=True
)
@set.subcommand(description="Registers the channel for verification messages.")
async def verify_channel(
@@ -386,8 +399,10 @@ class SetCog(commands.Cog, name="Set command."):
with Session(engine) as session:
stmt = select(Guild).where(col(Guild.id) == interaction.guild_id)
guild = session.scalar(stmt)
guild.VerificationChannel = channel_id
if (guild := session.scalar(stmt)) is None:
await interaction.response.send_message("Guild was not found.", ephemeral=True)
return
guild.verification_channel = channel_id
session.commit()
await interaction.send(f"Registered <#{channel_id}>.", ephemeral=True)
@@ -8,11 +8,11 @@ from sqlalchemy import select
from sqlalchemy.orm import Session
from sqlmodel import col
from cogs.submission.verification_view import VerificationView
from database.db import engine
from database.models import Category, CategoryGroup, Guild, Submission
from main import agon_logger
from utilities.utils import autofill_categories, autofill_groups, submit_score
from agon.cogs.submission.verification_view import VerificationView
from agon.database.db import engine
from agon.database.models import Category, CategoryGroup, Guild, Submission
from agon.logger import agon_logger
from agon.utils import autofill_categories, autofill_groups, submit_score
class SubmissionCog(commands.Cog):
@@ -64,10 +64,7 @@ class SubmissionCog(commands.Cog):
.where(col(Category.group_id) == int(group_id))
.where(col(Category.id) == int(category_id))
)
category: Category | None = session.scalar(stmt)
if category is None:
if (category := session.scalar(stmt)) is None:
await interaction.response.send_message("Category not found.", ephemeral=True)
return
@@ -79,10 +76,13 @@ class SubmissionCog(commands.Cog):
return
# check with regex if score is in correct format
verified_score = await self.verify_score(interaction, score, is_time_record=category.is_time_record)
# check if verify_score was successful. It replies with corrections required itself.
if verified_score is None:
if (
verified_score := await self.verify_score(interaction, score, is_time_record=category.is_time_record)
) is None:
# This response message will be filled out better once command is split up to
# know which type it expects...
await interaction.response.send_message("Format was incorrect.", ephemeral=True)
return
# Create submission verification request or submit score if verification not needed.
@@ -92,16 +92,13 @@ class SubmissionCog(commands.Cog):
return
stmt = select(col(Guild.verification_channel)).where(col(Guild.id) == interaction.guild_id)
verification_channel_id: int | None = session.scalar(stmt)
if verification_channel_id is None:
if (verification_channel_id := session.scalar(stmt)) is None:
error_response = "No verification channel was registered. Contact server admins."
await interaction.response.send_message(error_response, ephemeral=True)
return
channel = interaction.guild.get_channel(verification_channel_id)
if channel is None:
if (channel := interaction.guild.get_channel(verification_channel_id)) is None:
error_response = "Registered Verification channel does not exist. Contact server admins."
await interaction.response.send_message(error_response, ephemeral=True)
return
@@ -6,9 +6,9 @@ from sqlalchemy import select
from sqlalchemy.orm import Session
from sqlmodel import col
from database.db import engine
from database.models import Guild
from utilities.utils import autofill_users_in_guild
from agon.database.db import engine
from agon.database.models import Guild
from agon.utils import autofill_users_in_guild
from .views.update_username_verify import UpdateUsernameVerifyView
@@ -7,9 +7,9 @@ from sqlalchemy import select
from sqlalchemy.orm import Session
from sqlmodel import col
from database.db import engine
from database.models import Category, CategoryGroup, Score
from utilities.utils import MAX_LINE_LENGTH, autofill_categories, autofill_groups, format_score_string
from agon.database.db import engine
from agon.database.models import Category, CategoryGroup, Score
from agon.utils import MAX_LINE_LENGTH, autofill_categories, autofill_groups, format_score_string
class ViewCog(commands.Cog, name="View Command"):
@@ -4,9 +4,9 @@ import nextcord
from sqlalchemy import delete, select
from sqlalchemy.orm import Session
from database.db import engine
from database.models import Category, CategoryGroup
from utilities.utils import send_highscore_message
from agon.database.db import engine
from agon.database.models import Category, CategoryGroup
from agon.utils import send_highscore_message
class DeleteConfirmView(nextcord.ui.Modal):
@@ -5,9 +5,9 @@ from sqlalchemy import distinct, exc, select
from sqlalchemy.orm import Session
from sqlmodel import col
from database.db import engine
from database.models import Category, CategoryGroup, Score
from utilities.utils import send_highscore_message
from agon.database.db import engine
from agon.database.models import Category, CategoryGroup, Score
from agon.utils import send_highscore_message
class UpdateUsernameVerifyView(nextcord.ui.View):
@@ -6,8 +6,8 @@ from sqlalchemy import select
from sqlalchemy.orm import Session
from sqlmodel import col
from database.db import engine
from database.models import Guild
from agon.database.db import engine
from agon.database.models import Guild
class GuildListener(commands.Cog, name="Guild Listener"):
@@ -26,10 +26,9 @@ class GuildListener(commands.Cog, name="Guild Listener"):
"""
with Session(engine) as session:
stmt = select(Guild).where(col(Guild.id == guild.id))
guild_data = session.scalar(stmt)
# just in case check if the guild already exists
if guild_data is None:
if (guild_data := session.scalar(stmt)) is None:
new_guild = Guild(id=guild.id, name=guild.name)
session.add(new_guild)
else:
@@ -5,8 +5,8 @@ from sqlalchemy import select
from sqlalchemy.orm import Session
from sqlmodel import col
from database.db import engine
from database.models import Guild
from agon.database.db import engine
from agon.database.models import Guild
class GuildData(commands.Cog, name="Guild Data"):
@@ -31,7 +31,7 @@ class GuildData(commands.Cog, name="Guild Data"):
with Session(engine) as session:
for guild in self.bot.guilds:
# update given guild name for guild id
stmt = select(Guild).where(col(Guild.id == guild.id))
stmt = select(Guild).where(col(Guild.id) == guild.id)
guild_data = session.scalar(stmt)
# just in case checking if the guild doesn't exist.
@@ -39,6 +39,6 @@ class GuildData(commands.Cog, name="Guild Data"):
new_guild = Guild(id=guild.id, name=guild.name)
session.add(new_guild)
else:
guild_data.GuildName = guild.name
guild_data.name = guild.name
session.commit()
@@ -5,9 +5,9 @@ from sqlalchemy import delete, select
from sqlalchemy.orm import Session
from sqlmodel import col
from database.db import engine
from database.models import Submission
from utilities.utils import submit_score
from agon.database.db import engine
from agon.database.models import Submission
from agon.utils import submit_score
class VerificationView(nextcord.ui.View):
@@ -39,9 +39,7 @@ class VerificationView(nextcord.ui.View):
.where(col(Submission.message_id) == interaction.message.id)
)
submission = session.scalar(stmt)
if submission is None:
if (submission := session.scalar(stmt)) is None:
await interaction.response.send_message("Could not find submission data in database.", ephemeral=True)
await interaction.message.delete()
return
+6 -2
View File
@@ -1,14 +1,18 @@
"""Simple file to set up the sqlmodel connection to database."""
from sqlmodel import SQLModel, create_engine
from utilities import config
from agon import config
from agon.logger import agon_logger
from . import models # noqa: F401 - Need this import for creating the models.
if config.ENVIRONMENT == "prod":
url = f"mysql+pymysql://{config.SQL_USER}:{config.SQL_PASS}@{config.SQL_HOST}/{config.SQL_DB}"
agon_logger.info("Connected to prod database.")
else:
url = "sqlite:///database.db"
url = "sqlite:///database/database.db"
agon_logger.info("Connected to local dev database.")
engine = create_engine(url)
# Don't need to create all when connected to prod.
+6 -6
View File
@@ -8,9 +8,9 @@ from sqlalchemy import distinct, select
from sqlalchemy.orm import Session, aliased
from sqlmodel import col
from database.db import engine
from database.models import Category, CategoryGroup, Guild, Score
from main import agon_logger
from agon.database.db import engine
from agon.database.models import Category, CategoryGroup, Guild, Score
from agon.logger import agon_logger
MAX_LINE_LENGTH = 142
@@ -65,7 +65,7 @@ def autofill_groups(guild_id: int, group_begin: str) -> "dict[str, str]":
"""
with Session(engine) as session:
# Select all groups in guild.
stmt = select(CategoryGroup).wherecol((CategoryGroup.guild_id) == guild_id)
stmt = select(CategoryGroup).where(col(CategoryGroup.guild_id) == guild_id)
# dict has to have key values of same type for discord.
group_dict: dict[str, str] = {group.name: str(group.id) for group in session.scalars(stmt)}
@@ -353,7 +353,7 @@ async def send_highscore_message(session: Session, guild: nextcord.Guild, group:
if group.message_id is None:
# message doesn't exist.
message: nextcord.Message = await channel.send(highscore_string)
group.MessageId = message.id
group.message_id = message.id
session.commit()
else:
# TODO(imcompiling): check what happens when message is deleted.
@@ -398,7 +398,7 @@ async def submit_score(
existing_score = session.scalar(stmt)
if existing_score:
existing_score.Score = score_f
existing_score.score = score_f
else:
score_obj = Score(username=username, score=score_f, category_id=category_id)
session.add(score_obj)
-40
View File
@@ -1,40 +0,0 @@
import os
from dotenv import load_dotenv
from sqlmodel import Session, SQLModel, create_engine, select
from models import CategoryGroup, Guild
load_dotenv()
SQL_DB = os.getenv("SQL_DB", "")
SQL_HOST = os.getenv("SQL_HOST", "")
SQL_PASS = os.getenv("SQL_PASS", "")
SQL_USER = os.getenv("SQL_USER", "")
url = "sqlite:///database.db"
# url = f"mysql+pymysql://{SQL_USER}:{SQL_PASS}@{SQL_HOST}/{SQL_DB}"
engine = create_engine(url)
SQLModel.metadata.create_all(engine)
with Session(engine) as session:
guild = Guild(id=1, name="test guild")
session.add(guild)
group1 = CategoryGroup(name="group1", channel_id=1, guild_id=1, message_id=1)
group2 = CategoryGroup(name="group2", channel_id=2, guild_id=1, message_id=2)
session.add(group1)
session.add(group2)
session.commit()
# anotherone = Guild(id=2, name="test guild 2", submission_channel=1, verification_channel=2)
# session.add(anotherone)
# group1 = CategoryGroup(name="group1", channel_id=1, guild_id=2, message_id=1)
# group2 = CategoryGroup(name="group2", channel_id=2, guild_id=2, message_id=2)
# session.add(group1)
# session.add(group2)
# session.commit()
stmt = select(Guild).where(Guild.name == "Dakiny")
guild = session.scalar(stmt)
print(guild.category_groups)
-7
View File
@@ -1,7 +0,0 @@
[tool.ruff]
# Extend the `pyproject.toml` file in the parent directory...
extend = "../pyproject.toml"
[tool.ruff.lint]
# ignore implicit-namespace-package in this directory.
ignore = ["INP001"]
-56
View File
@@ -1,56 +0,0 @@
CREATE DATABASE highscores;
use highscores;
CREATE TABLE Guilds(
GuildId bigint unsigned not null unique,
GuildName varchar(95) not null,
SubmissionChannel bigint unsigned, -- deprecated, is not used anymore.
VerificationChannel bigint unsigned,
Active boolean DEFAULT true,
PRIMARY KEY (GuildId)
);
CREATE TABLE CategoryGroups(
GroupId int unsigned not null unique AUTO_INCREMENT,
GroupName varchar(50) not null,
ChannelId bigint unsigned,
GuildId bigint unsigned not null,
MessageId bigint unsigned,
PadLength smallint not null DEFAULT 26,
UsernameLength smallint DEFAULT 12,
CONSTRAINT UniqueGuildCategoryGroup UNIQUE (GuildId, GroupName),
FOREIGN KEY (GuildId) REFERENCES Guilds(GuildId) ON DELETE CASCADE,
PRIMARY KEY (GroupId)
);
CREATE TABLE Categories(
CategoryId int unsigned not null unique AUTO_INCREMENT,
CategoryName varchar(30) not null,
GroupId int unsigned not null,
Size smallint not null DEFAULT 3,
IsAscending boolean not null DEFAULT true,
IsTimeRecord boolean not null DEFAULT false,
IsValidated boolean not null DEFAULT true,
CONSTRAINT UniqueCategoryInGroup UNIQUE (GroupId, CategoryName),
FOREIGN KEY (GroupId) REFERENCES CategoryGroups(GroupId) ON DELETE CASCADE,
PRIMARY Key (CategoryId)
);
CREATE TABLE Scores(
UserName varchar(30) not null,
Score float not null, -- Maybe should have time and int scores?? timestamp type?
CategoryId int unsigned not null,
FOREIGN KEY (CategoryId) REFERENCES Categories(CategoryId) ON DELETE CASCADE,
PRIMARY KEY (CategoryId, UserName)
);
CREATE TABLE Submissions(
CategoryId int unsigned not null,
GroupId int unsigned not null,
GuildId bigint unsigned not null,
MessageId bigint unsigned not null,
Score varchar(30) not null, -- Score is stored as a string until converted during submission
UserId bigint unsigned not null,
UserName varchar(30) not null,
PRIMARY KEY (CategoryId, UserName) -- one submission a category per user.
);
-1
View File
@@ -1 +0,0 @@
"""Package of utility functions and environment configuration variables."""