9 Commits
Author SHA1 Message Date
imcompiling f79d63c78d Add timestamp to description.
build_develop / build (push) Successful in 22s
2025-03-20 09:27:36 -04:00
imcompiling 5a8119f5e4 Add the daily loop for open raid.
build_develop / build (push) Successful in 22s
2025-03-19 21:27:58 -04:00
imcompiling d5e6ffdedb Correct raid time.
build_develop / build (push) Successful in 21s
2025-03-19 19:36:21 -04:00
imcompiling 661c864ba2 Edit a docustring. 2025-03-19 19:19:34 -04:00
imcompiling 8d65d478cd Add function to open raid buttons. Load the view in app so that views function after bot restart.
build_develop / build (push) Successful in 22s
2025-03-19 19:16:17 -04:00
imcompiling 10e561b0e3 Update the button looks. 2025-03-19 18:04:49 -04:00
imcompiling 842a385d7d Add test cog to commands init. 2025-03-19 17:49:34 -04:00
imcompiling e9c8336124 Add module that will support open raid. Add test command.
build_develop / build (push) Successful in 21s
2025-03-19 11:39:26 -04:00
imcompiling ef92902932 Add utils to define guild ids that will use this bot. 2025-03-19 11:39:08 -04:00
12 changed files with 241 additions and 8 deletions
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+8 -2
View File
@@ -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
View File
@@ -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
+3
View File
@@ -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))
+2 -1
View File
@@ -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."""
+43
View File
@@ -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())
+23 -1
View File
@@ -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()
+151
View File
@@ -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
+1
View File
@@ -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
+3
View File
@@ -0,0 +1,3 @@
"""File contains functions and variables used widely."""
GUILDS = [1000247361639030804, 822199658306076672]