Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ BOT_MISC_COOLDOWN=20
BOT_OPENAI_COOLDOWN=10
BOT_OWNER_COOLDOWN=5


# OpenAI API key
BOT_OPENAI_MODEL=gpt-5.2
OPENAI_API_KEY=


# ddcDatabases configs
POSTGRESQL_HOST=postgres
POSTGRESQL_PORT=5432
Expand Down Expand Up @@ -55,6 +57,7 @@ POSTGRESQL_OP_INITIAL_RETRY_DELAY=0.5
POSTGRESQL_OP_MAX_RETRY_DELAY=10.0
POSTGRESQL_OP_JITTER=0.1


# pythonLogs configs
LOG_LEVEL=INFO
LOG_TIMEZONE=UTC
Expand All @@ -72,6 +75,7 @@ LOG_LOGGER_TTL_SECONDS=1800
LOG_ROTATE_WHEN=midnight
LOG_ROTATE_AT_UTC=True


# GW2 configuration
GW2_API_VERSION=2
GW2_EMBED_COLOR=green
Expand Down
6 changes: 0 additions & 6 deletions .github/PULL_REQUEST_TEMPLATE
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,7 @@
- [ ] Other

## Testing
- [ ] Unit tests added/updated
- [ ] Integration tests added/updated
- [ ] Manual testing performed

## Checklist
- [ ] Documentation updated (if applicable)
- [ ] I have considered how this change may affect other services

## Reviewer
- [ ] I understand that by approving this PR, I share responsibility for these changes
10 changes: 4 additions & 6 deletions .github/workflows/workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ jobs:
docker:
name: Docker
runs-on: ubuntu-latest
needs: lint
steps:
- uses: actions/checkout@v6

Expand Down Expand Up @@ -109,7 +110,7 @@ jobs:
pages:
name: Deploy Pages
runs-on: ubuntu-latest
needs: [test, integration-test]
needs: [test, integration-test, docker]
if: startsWith(github.ref, 'refs/tags/v')
permissions:
pages: write
Expand Down Expand Up @@ -148,7 +149,7 @@ jobs:
release:
name: Create Release
runs-on: ubuntu-latest
needs: [test, integration-test]
needs: [test, integration-test, docker]
if: startsWith(github.ref, 'refs/tags/v')
permissions:
contents: write
Expand All @@ -157,7 +158,4 @@ jobs:
uses: softprops/action-gh-release@v2
with:
name: Release ${{ github.ref_name }}
body: |
Automated release for version ${{ github.ref_name }}
draft: false
prerelease: false
generate_release_notes: true
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,4 @@ cython_debug/

# Local logs
/logs/*
/requirements.txt
20 changes: 20 additions & 0 deletions .snyk
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Snyk policy file
# https://docs.snyk.io/scan-using-snyk/snyk-code/configure-snyk-code#excluding-directories-and-files-from-the-snyk-code-test
version: v1.25.0
exclude:
global:
- tests/**
ignore:
'snyk:lic:pip:psycopg:LGPL-3.0':
- '*':
reason: psycopg is used as a dependency, not modified - LGPL-3.0 is compatible with MIT
expires: 2027-03-20T00:00:00.000Z
'snyk:lic:pip:psycopg-binary:LGPL-3.0':
- '*':
reason: psycopg-binary is used as a dependency, not modified - LGPL-3.0 is compatible with MIT
expires: 2027-03-20T00:00:00.000Z
'snyk:lic:pip:certifi:MPL-2.0':
- '*':
reason: certifi is used as a dependency, not modified - MPL-2.0 is compatible with MIT
expires: 2027-03-20T00:00:00.000Z

5 changes: 3 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ ENV LOG_DIRECTORY="${LOG_DIRECTORY}" \
WORKDIR ${WORKDIR}

RUN set -ex && \
apk upgrade --no-cache zlib && \
apk update && \
apk upgrade --no-cache && \
apk add --no-cache ca-certificates curl && \
curl --proto '=https' -LsSf https://astral.sh/uv/install.sh | sh && \
curl --proto '=https' --tlsv1.3 -LsSf https://astral.sh/uv/install.sh | sh && \
addgroup -g 1000 botuser && \
adduser -u 1000 -G botuser -h /home/botuser -D botuser && \
mv /root/.local /home/botuser/.local && \
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<p align="center">
<a href="https://github.com/sponsors/ddc"><img src="https://img.shields.io/static/v1?style=plastic&label=Sponsor&message=%E2%9D%A4&logo=GitHub&color=ff69b4" alt="Sponsor"/></a>
<br>
<a href="https://ko-fi.com/ddcsta"><img src="https://img.shields.io/badge/Ko--fi-ddcsta-FF5E5B?style=plastic&logo=kofi&logoColor=white&color=brightgreen" alt="Ko-fi"/></a>
<a href="https://ko-fi.com/ddc"><img src="https://img.shields.io/badge/Ko--fi-ddc-FF5E5B?style=plastic&logo=kofi&logoColor=white&color=brightgreen" alt="Ko-fi"/></a>
<a href="https://www.paypal.com/ncp/payment/6G9Z78QHUD4RJ"><img src="https://img.shields.io/badge/Donate-PayPal-brightgreen.svg?style=plastic&logo=paypal&logoColor=white" alt="Donate"/></a>
<br>
<a href="https://www.python.org/downloads"><img src="https://img.shields.io/badge/python-3.14-blue.svg?style=plastic&logo=python&logoColor=3776AB" alt="Python"/></a>
Expand Down Expand Up @@ -312,8 +312,8 @@ Released under the [MIT License](LICENSE)


# Support
If you find this project helpful, consider supporting development:
If you find this project helpful, consider supporting development.

- [GitHub Sponsor](https://github.com/sponsors/ddc)
- [ko-fi](https://ko-fi.com/ddcsta)
- [PayPal](https://www.paypal.com/ncp/payment/6G9Z78QHUD4RJ)
<a href='https://github.com/sponsors/ddc' target='_blank'><img height='24' style='border:0px;height:24px;' src='https://img.shields.io/badge/Sponsor-❤-ea4aaa?style=plastic&logo=github&logoColor=white' border='0' alt='Sponsor on GitHub' /></a>
<a href='https://ko-fi.com/ddc' target='_blank'><img height='30' style='border:0px;height:30px;' src='https://storage.ko-fi.com/cdn/kofi2.png?v=6' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
<a href='https://www.paypal.com/ncp/payment/6G9Z78QHUD4RJ' target='_blank'><img height='30' style='border:0px;height:30px;' src='https://www.paypalobjects.com/digitalassets/c/website/marketing/apac/C2/logos-buttons/optimize/44_Yellow_PayPal_Pill_Button.png' border='0' alt='Donate via PayPal' /></a>
24 changes: 13 additions & 11 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "DiscordBot"
version = "3.0.8"
version = "3.0.9"
description = "A simple Discord bot with OpenAI support and server administration tools"
urls.Repository = "https://github.com/ddc/DiscordBot"
urls.Homepage = "https://ddc.github.io/DiscordBot"
Expand Down Expand Up @@ -33,26 +33,29 @@ dependencies = [
"alembic>=1.18.4",
"beautifulsoup4>=4.14.3",
"better-profanity>=0.7.0",
"ddcdatabases[postgres]>=3.0.11",
"ddcdatabases[postgres]>=4.0.1",
"discord-py>=2.7.1",
"gTTS>=2.5.4",
"openai>=2.28.0",
"openai>=2.29.0",
"PyNaCl>=1.6.2",
"pythonLogs>=6.0.3",
"pythonLogs>=7.0.0",
"uuid-utils>=0.14.1",
]

[dependency-groups]
dev = [
"coverage>=7.13.4",
"coverage>=7.13.5",
"poethepoet>=0.42.1",
"pytest-asyncio>=1.3.0",
"ruff>=0.15.6",
"testcontainers[postgres]>=4.14.1",
"ruff>=0.15.7",
"testcontainers[postgres]>=4.14.2",
]

[tool.poe.tasks]
linter.shell = "uv run ruff check --fix . && uv run ruff format ."
snyk-export.shell = "rm -f requirements.txt && uv export --no-hashes --no-annotate --format requirements-txt > requirements.txt && uvx pre-commit run --all-files || uvx pre-commit run --all-files"
snyk-container.shell = "docker build -t discordbot:snyk-scan . && snyk container test discordbot:snyk-scan --file=Dockerfile; docker rmi discordbot:snyk-scan"
snyk.sequence = ["snyk-export", { shell = "uv pip install pip && snyk test --file=requirements.txt && snyk code test; uv pip uninstall pip" }, "snyk-container"]
profile = "uv run python -m cProfile -o cprofile_unit.prof -m pytest tests/unit"
profile-integration = "uv run python -m cProfile -o cprofile_integration.prof -m pytest tests/integration"
test.sequence = [{ shell = "uv run coverage run -m pytest tests/unit" }, { shell = "uv run coverage report" }, { shell = "uv run coverage xml" }]
Expand Down Expand Up @@ -100,15 +103,14 @@ line-length = 120
target-version = "py314"

[tool.ruff.lint]
select = ["E", "W", "F", "I", "B", "C4", "UP"]
select = ["E", "W", "F", "I", "B", "C4", "UP", "S", "SLF"]
ignore = ["E501", "E402", "UP046", "UP047"]

[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["F401"]
"tests/**/*.py" = ["S101", "S105", "S106", "S311", "SLF001", "F841"]
"tests/**/*.py" = ["S101", "S105", "S106", "S110", "S311", "S603", "S607", "SLF001", "F841"]

[tool.ruff.lint.isort]
known-first-party = ["DiscordBot"]
force-sort-within-sections = false
from-first = false
no-lines-before = ["future", "standard-library", "third-party", "first-party", "local-folder"]
no-sections = true
4 changes: 2 additions & 2 deletions src/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
import time
import traceback
from aiohttp import ClientSession
from ddcDatabases import PostgreSQL
from pythonLogs import TimedRotatingLog
from ddcdatabases import PostgreSQL
from pythonlogs import TimedRotatingLog
from src.bot.constants import messages, variables
from src.bot.constants.settings import get_bot_settings
from src.bot.discord_bot import Bot
Expand Down
4 changes: 2 additions & 2 deletions src/bot/constants/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@


class Bot:
TOKEN_NOT_FOUND = "BOT_TOKEN variable not found"
MISSING_ENV_VAR = "BOT_TOKEN variable not found"
TERMINATED = "Bot has been terminated."
STOPPED_CTRTC = "Bot stopped with Ctrl+C"
FATAL_ERROR_MAIN = "Fatal error in main()"
Expand Down Expand Up @@ -225,7 +225,7 @@ class Owner:
# ============================================================================

# Bot
BOT_TOKEN_NOT_FOUND = Bot.TOKEN_NOT_FOUND
BOT_TOKEN_NOT_FOUND = Bot.MISSING_ENV_VAR
BOT_TERMINATED = Bot.TERMINATED
BOT_STOPPED_CTRTC = Bot.STOPPED_CTRTC
BOT_FATAL_ERROR_MAIN = Bot.FATAL_ERROR_MAIN
Expand Down
2 changes: 1 addition & 1 deletion src/bot/constants/variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import sys
import tomllib
from pathlib import Path
from pythonLogs import get_log_settings
from pythonlogs import get_log_settings
from src.bot.constants.settings import get_bot_settings
from typing import Final

Expand Down
10 changes: 5 additions & 5 deletions src/bot/tools/custom_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def __init__(self, pages: list[str], author_id: int):
self.message: discord.Message | None = None
self._update_buttons()

def _format_page(self) -> str:
def format_page(self) -> str:
page_header = f"**Page {self.current_page + 1}/{len(self.pages)}**\n"
return page_header + self.pages[self.current_page]

Expand All @@ -31,7 +31,7 @@ async def previous_button(self, interaction: discord.Interaction, button: discor
)
self.current_page -= 1
self._update_buttons()
await interaction.response.edit_message(content=self._format_page(), view=self)
await interaction.response.edit_message(content=self.format_page(), view=self)

@discord.ui.button(label="1/1", style=discord.ButtonStyle.secondary, disabled=True)
async def page_indicator(self, interaction: discord.Interaction, button: discord.ui.Button):
Expand All @@ -45,7 +45,7 @@ async def next_button(self, interaction: discord.Interaction, button: discord.ui
)
self.current_page += 1
self._update_buttons()
await interaction.response.edit_message(content=self._format_page(), view=self)
await interaction.response.edit_message(content=self.format_page(), view=self)


class CustomHelpCommand(commands.DefaultHelpCommand):
Expand Down Expand Up @@ -131,7 +131,7 @@ async def _send_pages_to_dm(self):
await self.context.author.send(pages[0])
else:
view = HelpPaginatorView(pages, self.context.author.id)
msg = await self.context.author.send(content=view._format_page(), view=view)
msg = await self.context.author.send(content=view.format_page(), view=view)
view.message = msg

async def _send_pages_to_destination(self, destination):
Expand All @@ -141,5 +141,5 @@ async def _send_pages_to_destination(self, destination):
await destination.send(pages[0])
else:
view = HelpPaginatorView(pages, self.context.author.id)
msg = await destination.send(content=view._format_page(), view=view)
msg = await destination.send(content=view.format_page(), view=view)
view.message = msg
2 changes: 1 addition & 1 deletion src/database/dal/bot/bot_configs_dal.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import sqlalchemy as sa
from ddcDatabases import DBUtilsAsync
from ddcdatabases import DBUtilsAsync
from sqlalchemy.future import select
from src.database.models.bot_models import BotConfigs

Expand Down
2 changes: 1 addition & 1 deletion src/database/dal/bot/custom_commands_dal.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import sqlalchemy as sa
from ddcDatabases import DBUtilsAsync
from ddcdatabases import DBUtilsAsync
from sqlalchemy.future import select
from src.database.models.bot_models import CustomCommands

Expand Down
2 changes: 1 addition & 1 deletion src/database/dal/bot/dice_rolls_dal.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import sqlalchemy as sa
from ddcDatabases import DBUtilsAsync
from ddcdatabases import DBUtilsAsync
from sqlalchemy.future import select
from src.database.models.bot_models import DiceRolls

Expand Down
2 changes: 1 addition & 1 deletion src/database/dal/bot/profanity_filters_dal.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import sqlalchemy as sa
from ddcDatabases import DBUtilsAsync
from ddcdatabases import DBUtilsAsync
from sqlalchemy.future import select
from src.database.models.bot_models import ProfanityFilters

Expand Down
2 changes: 1 addition & 1 deletion src/database/dal/bot/servers_dal.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import discord
import sqlalchemy as sa
from ddcDatabases import DBUtilsAsync
from ddcdatabases import DBUtilsAsync
from sqlalchemy.dialects.postgresql import insert
from sqlalchemy.future import select
from src.database.models.bot_models import ProfanityFilters, Servers
Expand Down
2 changes: 1 addition & 1 deletion src/database/dal/gw2/gw2_configs_dal.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import sqlalchemy as sa
from ddcDatabases import DBUtilsAsync
from ddcdatabases import DBUtilsAsync
from sqlalchemy.future import select
from src.database.models.gw2_models import Gw2Configs

Expand Down
2 changes: 1 addition & 1 deletion src/database/dal/gw2/gw2_key_dal.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import sqlalchemy as sa
from ddcDatabases import DBUtilsAsync
from ddcdatabases import DBUtilsAsync
from sqlalchemy.future import select
from src.database.models.gw2_models import Gw2Keys

Expand Down
2 changes: 1 addition & 1 deletion src/database/dal/gw2/gw2_session_chars_dal.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from ddcDatabases import DBUtilsAsync
from ddcdatabases import DBUtilsAsync
from sqlalchemy import update
from sqlalchemy.future import select
from src.database.models.gw2_models import Gw2SessionCharDeaths
Expand Down
2 changes: 1 addition & 1 deletion src/database/dal/gw2/gw2_sessions_dal.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import sqlalchemy as sa
from ddcDatabases import DBUtilsAsync
from ddcdatabases import DBUtilsAsync
from sqlalchemy.future import select
from src.database.models.gw2_models import Gw2SessionCharDeaths, Gw2Sessions

Expand Down
2 changes: 1 addition & 1 deletion src/database/migrations/env.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from alembic import context
from alembic.script import ScriptDirectory
from ddcDatabases import get_postgresql_settings
from ddcdatabases import get_postgresql_settings
from logging.config import fileConfig
from sqlalchemy import create_engine, engine_from_config, pool, text
from sqlalchemy.schema import SchemaItem
Expand Down
2 changes: 1 addition & 1 deletion src/database/migrations/versions/0001_create_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from alembic import op
from collections.abc import Sequence
from ddcDatabases.postgresql import get_postgresql_settings
from ddcdatabases.postgresql import get_postgresql_settings

revision: str = "0001"
down_revision: str | None = None
Expand Down
2 changes: 1 addition & 1 deletion src/gw2/cogs/key.py
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ async def info(ctx):
is_valid_key = await gw2_api.check_api_key(api_key)
if not isinstance(is_valid_key, dict):
is_valid_key = "NO"
name = f"***{gw2_messages.INVALID_API_KEY}***"
name = f"***{gw2_messages.INVALID_APIKEY_MSG}***"
else:
is_valid_key = "YES"
name = f"{ctx.message.author}"
Expand Down
2 changes: 1 addition & 1 deletion src/gw2/constants/gw2_messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#################################
# GW2 API
#################################
INVALID_API_KEY = "This API Key is INVALID or no longer exists in gw2 api database"
INVALID_APIKEY_MSG = "This API Key is INVALID or no longer exists in gw2 api database"
API_ERROR = "GW2 API ERROR"
API_DOWN = "GW2 API is currently down. Try again later."
API_NOT_FOUND = "GW2 API Not found."
Expand Down
4 changes: 2 additions & 2 deletions src/gw2/tools/gw2_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,13 @@ async def _handle_api_error(self, response, endpoint):
def _handle_400_error(self, status, err_msg, init_msg):
"""Handle 400 Bad Request errors."""
if err_msg == "invalid key":
raise APIInvalidKey(self.bot, f"({status}) {gw2_messages.INVALID_API_KEY}")
raise APIInvalidKey(self.bot, f"({status}) {gw2_messages.INVALID_APIKEY_MSG}")
raise APIBadRequest(self.bot, f"({init_msg}) {gw2_messages.API_DOWN}")

def _handle_403_error(self, status, err_msg, init_msg):
"""Handle 403 Forbidden errors."""
if err_msg == "invalid key":
raise APIInvalidKey(self.bot, f"({status}) {gw2_messages.INVALID_API_KEY}")
raise APIInvalidKey(self.bot, f"({status}) {gw2_messages.INVALID_APIKEY_MSG}")
raise APIForbidden(self.bot, f"({init_msg}) {gw2_messages.API_ACCESS_DENIED}")

def _handle_404_error(self, status, endpoint):
Expand Down
Loading
Loading