Archived
generated from imcompiling/discord-bot-template
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f79d63c78d | ||
|
|
5a8119f5e4 | ||
|
|
d5e6ffdedb | ||
|
|
661c864ba2 | ||
|
|
8d65d478cd | ||
|
|
10e561b0e3 | ||
|
|
842a385d7d | ||
|
|
e9c8336124 | ||
|
|
ef92902932 |
@@ -13,7 +13,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Code
|
- name: Checkout Code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Install Docker
|
- name: Install Docker
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Code
|
- name: Checkout Code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Install Docker
|
- name: Install Docker
|
||||||
|
|||||||
Vendored
+7
-1
@@ -4,5 +4,11 @@
|
|||||||
"reportArgumentType": "information",
|
"reportArgumentType": "information",
|
||||||
"reportAttributeAccessIssue": "warning"
|
"reportAttributeAccessIssue": "warning"
|
||||||
},
|
},
|
||||||
"cSpell.words": ["cakeday", "cakedays", "cooldown", "nextcord"]
|
"cSpell.words": [
|
||||||
|
"blurple",
|
||||||
|
"cakeday",
|
||||||
|
"cakedays",
|
||||||
|
"cooldown",
|
||||||
|
"nextcord"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
FROM python:3.13.3-slim
|
FROM python:3.12.3-slim
|
||||||
|
|
||||||
# install uv
|
# install uv
|
||||||
COPY --from=ghcr.io/astral-sh/uv:0.6.17 /uv /uvx /bin/
|
COPY --from=ghcr.io/astral-sh/uv:0.6.5 /uv /uvx /bin/
|
||||||
|
|
||||||
COPY . /home
|
COPY . /home
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import pathlib
|
|||||||
import nextcord
|
import nextcord
|
||||||
from nextcord.ext import commands
|
from nextcord.ext import commands
|
||||||
|
|
||||||
|
from off_cooldown_bot.open_raid import OpenRaid
|
||||||
|
|
||||||
from .logger import ocd_logger
|
from .logger import ocd_logger
|
||||||
from .settings import settings
|
from .settings import settings
|
||||||
|
|
||||||
@@ -40,6 +42,7 @@ def run() -> None:
|
|||||||
if bot.user is None:
|
if bot.user is None:
|
||||||
ocd_logger.critical("Discord connection failed.")
|
ocd_logger.critical("Discord connection failed.")
|
||||||
return
|
return
|
||||||
|
bot.add_view(OpenRaid())
|
||||||
ocd_logger.info("%s has connected to Discord!", bot.user.name)
|
ocd_logger.info("%s has connected to Discord!", bot.user.name)
|
||||||
|
|
||||||
# Run Discord bot
|
# Run Discord bot
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
from nextcord.ext import commands
|
from nextcord.ext import commands
|
||||||
|
|
||||||
|
from off_cooldown_bot.cogs.commands.test import TestCog
|
||||||
|
|
||||||
from .birthday import BirthdayCog
|
from .birthday import BirthdayCog
|
||||||
|
|
||||||
|
|
||||||
@@ -10,3 +12,4 @@ from .birthday import BirthdayCog
|
|||||||
def setup(bot: commands.Bot) -> None:
|
def setup(bot: commands.Bot) -> None:
|
||||||
"""Add all command classes to bot."""
|
"""Add all command classes to bot."""
|
||||||
bot.add_cog(BirthdayCog())
|
bot.add_cog(BirthdayCog())
|
||||||
|
bot.add_cog(TestCog(bot))
|
||||||
|
|||||||
@@ -10,12 +10,13 @@ from sqlmodel import Session, col, select
|
|||||||
from off_cooldown_bot.app import birthday_list
|
from off_cooldown_bot.app import birthday_list
|
||||||
from off_cooldown_bot.database.db import engine
|
from off_cooldown_bot.database.db import engine
|
||||||
from off_cooldown_bot.database.models import UserBirthday
|
from off_cooldown_bot.database.models import UserBirthday
|
||||||
|
from off_cooldown_bot.utils import GUILDS
|
||||||
|
|
||||||
|
|
||||||
class BirthdayCog(commands.Cog, name="Birthday Commands"):
|
class BirthdayCog(commands.Cog, name="Birthday Commands"):
|
||||||
"""Class holds birthday commands."""
|
"""Class holds birthday commands."""
|
||||||
|
|
||||||
@nextcord.slash_command(guild_ids=[1000247361639030804, 822199658306076672])
|
@nextcord.slash_command(guild_ids=GUILDS)
|
||||||
async def birthday(self, interaction: nextcord.Interaction) -> None:
|
async def birthday(self, interaction: nextcord.Interaction) -> None:
|
||||||
"""Parent slash command for birthday. Never called."""
|
"""Parent slash command for birthday. Never called."""
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
"""Commands for testing."""
|
||||||
|
|
||||||
|
import nextcord
|
||||||
|
from nextcord.ext import application_checks, commands
|
||||||
|
|
||||||
|
from off_cooldown_bot.open_raid import OpenRaid, build_raid_embed
|
||||||
|
from off_cooldown_bot.utils import GUILDS
|
||||||
|
|
||||||
|
ME = 206602713511886849
|
||||||
|
|
||||||
|
|
||||||
|
def is_me(): # noqa: ANN201
|
||||||
|
"""Predicate that makes sure only I can run the test commands."""
|
||||||
|
|
||||||
|
def predicate(interaction: nextcord.Interaction) -> bool:
|
||||||
|
if interaction.user is None:
|
||||||
|
return False
|
||||||
|
return interaction.user.id == ME
|
||||||
|
|
||||||
|
return application_checks.check(predicate)
|
||||||
|
|
||||||
|
|
||||||
|
class TestCog(commands.Cog, name="Test commands."):
|
||||||
|
"""Class holds commands for testing."""
|
||||||
|
|
||||||
|
def __init__(self, bot: commands.Bot) -> None:
|
||||||
|
self.bot: commands.Bot = bot
|
||||||
|
|
||||||
|
@nextcord.slash_command(guild_ids=GUILDS)
|
||||||
|
async def test(self, interaction: nextcord.Interaction) -> None:
|
||||||
|
"""Parent slash command for help. Never called."""
|
||||||
|
|
||||||
|
@test.subcommand()
|
||||||
|
@is_me()
|
||||||
|
async def open_raid(self, interaction: nextcord.Interaction) -> None:
|
||||||
|
"""
|
||||||
|
Force starts election.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
interaction (nextcord.Interaction): Interaction with the message.
|
||||||
|
|
||||||
|
"""
|
||||||
|
await interaction.response.send_message("Starting an open raid.", embed=build_raid_embed(), view=OpenRaid())
|
||||||
@@ -13,6 +13,7 @@ from off_cooldown_bot.app import birthday_list
|
|||||||
from off_cooldown_bot.database.db import engine
|
from off_cooldown_bot.database.db import engine
|
||||||
from off_cooldown_bot.database.models import UserBirthday
|
from off_cooldown_bot.database.models import UserBirthday
|
||||||
from off_cooldown_bot.logger import ocd_logger
|
from off_cooldown_bot.logger import ocd_logger
|
||||||
|
from off_cooldown_bot.open_raid import OpenRaid, build_raid_embed
|
||||||
from off_cooldown_bot.settings import settings
|
from off_cooldown_bot.settings import settings
|
||||||
|
|
||||||
|
|
||||||
@@ -25,14 +26,35 @@ class DailyLoop(commands.Cog, name="Daily Loop"):
|
|||||||
self.update_birthdays()
|
self.update_birthdays()
|
||||||
self.daily_loop.start()
|
self.daily_loop.start()
|
||||||
|
|
||||||
@tasks.loop(time=time(hour=0, tzinfo=timezone("UTC")))
|
@tasks.loop(time=time(hour=0, tzinfo=UTC))
|
||||||
async def daily_loop(self) -> None:
|
async def daily_loop(self) -> None:
|
||||||
"""Run daily repeated functions."""
|
"""Run daily repeated functions."""
|
||||||
self.update_birthdays()
|
self.update_birthdays()
|
||||||
|
|
||||||
await self.cakedays()
|
await self.cakedays()
|
||||||
|
|
||||||
|
@tasks.loop(time=time(hour=20, tzinfo=timezone("CST")))
|
||||||
|
async def open_raid(self) -> None:
|
||||||
|
"""
|
||||||
|
Define the open raid loop.
|
||||||
|
|
||||||
|
Checks daily if it is Thursday and then posts the open raid sign up.
|
||||||
|
"""
|
||||||
|
today = datetime.now(timezone("CST"))
|
||||||
|
if today.day + 2 == 5:
|
||||||
|
# open raid is on Saturday, post 2 days before
|
||||||
|
if (guild := self.bot.get_guild(settings.params.guild_id)) is None:
|
||||||
|
ocd_logger.error("Guild id not correct.")
|
||||||
|
return
|
||||||
|
if (channel := guild.get_channel(settings.channel_ids.raid)) is None or not isinstance(
|
||||||
|
channel, nextcord.TextChannel
|
||||||
|
):
|
||||||
|
ocd_logger.error("Raid channel is not defined or is not a text channel.")
|
||||||
|
return
|
||||||
|
await channel.send(embed=build_raid_embed(), view=OpenRaid())
|
||||||
|
|
||||||
@daily_loop.before_loop
|
@daily_loop.before_loop
|
||||||
|
@open_raid.before_loop
|
||||||
async def before_loop(self) -> None:
|
async def before_loop(self) -> None:
|
||||||
"""Actions run before the loop starts. Want to wait for bot to be ready and get the current cycle."""
|
"""Actions run before the loop starts. Want to wait for bot to be ready and get the current cycle."""
|
||||||
await self.bot.wait_until_ready()
|
await self.bot.wait_until_ready()
|
||||||
|
|||||||
@@ -0,0 +1,151 @@
|
|||||||
|
"""Contains functions for open raid sign-ups."""
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
import nextcord
|
||||||
|
|
||||||
|
from off_cooldown_bot.logger import ocd_logger
|
||||||
|
|
||||||
|
MAX_TANKS = 2
|
||||||
|
MAX_HEALERS = 2
|
||||||
|
MAX_DPS = 25
|
||||||
|
|
||||||
|
|
||||||
|
class OpenRaid(nextcord.ui.View):
|
||||||
|
"""Class defines view for buttons on an open raid schedule message."""
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super().__init__(timeout=None, auto_defer=True)
|
||||||
|
|
||||||
|
@nextcord.ui.button(label="Tank", style=nextcord.ButtonStyle.blurple, emoji="🛡️", custom_id="open_raid_tank")
|
||||||
|
async def tank(self, button: nextcord.ui.Button, interaction: nextcord.Interaction) -> None: # noqa: ARG002
|
||||||
|
"""
|
||||||
|
Signs a user up as a tank.
|
||||||
|
|
||||||
|
Removes them if they are already signed up.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
button (nextcord.ui.Button): Un-used.
|
||||||
|
interaction (nextcord.Interaction): Interaction with command.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if interaction.message is None or interaction.user is None:
|
||||||
|
ocd_logger.warning("Command was called without a message or user.")
|
||||||
|
return
|
||||||
|
|
||||||
|
embed = interaction.message.embeds[0]
|
||||||
|
user_str = f"<@{interaction.user.id}>"
|
||||||
|
|
||||||
|
for index, field in enumerate(embed.fields):
|
||||||
|
if field.name == "Tanks":
|
||||||
|
values = [] if field.value is None else field.value.split("\n")
|
||||||
|
if user_str in values:
|
||||||
|
values.remove(user_str)
|
||||||
|
else:
|
||||||
|
if len(values) >= MAX_TANKS:
|
||||||
|
await interaction.response.send_message(
|
||||||
|
"Enough tanks have signed up, please choose another role.", ephemeral=True
|
||||||
|
)
|
||||||
|
return
|
||||||
|
values.append(user_str)
|
||||||
|
embed.set_field_at(index, name=field.name, value="\n".join(values), inline=False)
|
||||||
|
break
|
||||||
|
|
||||||
|
await interaction.edit(embed=embed)
|
||||||
|
|
||||||
|
@nextcord.ui.button(label="Healer", style=nextcord.ButtonStyle.green, emoji="❤️", custom_id="open_raid_healer")
|
||||||
|
async def healer(self, button: nextcord.ui.Button, interaction: nextcord.Interaction) -> None: # noqa: ARG002
|
||||||
|
"""
|
||||||
|
Signs a user up as a healer.
|
||||||
|
|
||||||
|
Removes them if they are already signed up.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
button (nextcord.ui.Button): Un-used.
|
||||||
|
interaction (nextcord.Interaction): Interaction with command.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if interaction.message is None or interaction.user is None:
|
||||||
|
ocd_logger.warning("Command was called without a message or user.")
|
||||||
|
return
|
||||||
|
|
||||||
|
embed = interaction.message.embeds[0]
|
||||||
|
user_str = f"<@{interaction.user.id}>"
|
||||||
|
|
||||||
|
for index, field in enumerate(embed.fields):
|
||||||
|
if field.name == "Healers":
|
||||||
|
values = [] if field.value is None else field.value.split("\n")
|
||||||
|
if user_str in values:
|
||||||
|
values.remove(user_str)
|
||||||
|
else:
|
||||||
|
if len(values) >= MAX_HEALERS:
|
||||||
|
await interaction.response.send_message(
|
||||||
|
"Enough healers have signed up, please choose another role.", ephemeral=True
|
||||||
|
)
|
||||||
|
return
|
||||||
|
values.append(user_str)
|
||||||
|
embed.set_field_at(index, name=field.name, value="\n".join(values), inline=False)
|
||||||
|
break
|
||||||
|
|
||||||
|
await interaction.edit(embed=embed)
|
||||||
|
|
||||||
|
@nextcord.ui.button(label="DPS", style=nextcord.ButtonStyle.red, emoji="⚔️", custom_id="open_raid_dps")
|
||||||
|
async def dps(self, button: nextcord.ui.Button, interaction: nextcord.Interaction) -> None: # noqa: ARG002
|
||||||
|
"""
|
||||||
|
Signs a user up as dps.
|
||||||
|
|
||||||
|
Removes them if they are already signed up.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
button (nextcord.ui.Button): Un-used.
|
||||||
|
interaction (nextcord.Interaction): Interaction with command.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if interaction.message is None or interaction.user is None:
|
||||||
|
ocd_logger.warning("Command was called without a message or user.")
|
||||||
|
return
|
||||||
|
|
||||||
|
embed = interaction.message.embeds[0]
|
||||||
|
user_str = f"<@{interaction.user.id}>"
|
||||||
|
|
||||||
|
for index, field in enumerate(embed.fields):
|
||||||
|
if field.name == "DPS":
|
||||||
|
values = [] if field.value is None else field.value.split("\n")
|
||||||
|
if user_str in values:
|
||||||
|
values.remove(user_str)
|
||||||
|
else:
|
||||||
|
if len(values) >= MAX_DPS:
|
||||||
|
await interaction.response.send_message(
|
||||||
|
"Enough dps have signed up, please choose another role.", ephemeral=True
|
||||||
|
)
|
||||||
|
return
|
||||||
|
values.append(user_str)
|
||||||
|
embed.set_field_at(index, name=field.name, value="\n".join(values), inline=False)
|
||||||
|
break
|
||||||
|
|
||||||
|
await interaction.edit(embed=embed)
|
||||||
|
|
||||||
|
|
||||||
|
def build_raid_embed() -> nextcord.Embed:
|
||||||
|
"""
|
||||||
|
Build the open raid embed.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
nextcord.Embed: Embed that shows the raid's sign-ups.
|
||||||
|
|
||||||
|
"""
|
||||||
|
today = datetime.datetime.now(tz=datetime.UTC).replace(hour=20)
|
||||||
|
saturday_idx = 5
|
||||||
|
days_delta = saturday_idx - today.weekday()
|
||||||
|
if days_delta < 0:
|
||||||
|
days_delta += 7
|
||||||
|
raid_time = today + datetime.timedelta(days_delta)
|
||||||
|
|
||||||
|
embed = nextcord.Embed(
|
||||||
|
title="Off Cooldown Open Raid", description=f"Raid time: t:{int(raid_time.timestamp())}:F", timestamp=raid_time
|
||||||
|
)
|
||||||
|
embed.add_field(name="Tanks", value="", inline=False)
|
||||||
|
embed.add_field(name="Healers", value="", inline=False)
|
||||||
|
embed.add_field(name="DPS", value="", inline=False)
|
||||||
|
|
||||||
|
return embed
|
||||||
@@ -12,6 +12,7 @@ class ChannelIds:
|
|||||||
"""Class holds all channel ids needed by bot."""
|
"""Class holds all channel ids needed by bot."""
|
||||||
|
|
||||||
general: int
|
general: int
|
||||||
|
raid: int
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
"""File contains functions and variables used widely."""
|
||||||
|
|
||||||
|
GUILDS = [1000247361639030804, 822199658306076672]
|
||||||
Reference in New Issue
Block a user