Compare commits

..
Author SHA1 Message Date
imcompiling 8ff53d9a13 Grammar corrections.
build_develop / build (push) Has been cancelled
2023-10-05 14:26:15 -04:00
imcompiling 9609837b1d Control user reactions in election channel. 2023-10-05 14:24:33 -04:00
imcompiling 8cf66351dd Allow clan members to send messages to new channel.
build_develop / build (push) Has been cancelled
2023-09-20 20:14:32 -04:00
imcompiling a4c02b2f77 Change develop build to make a branch specific image.
build_latest / build (push) Successful in 1m27s
build_release / build (push) Successful in 45s
build_develop / build (push) Successful in 45s
2023-09-15 09:53:45 -04:00
imcompiling 8d8af9ab35 Change cakeday to be put in general channel. 2023-09-15 09:42:58 -04:00
imcompiling f70a7989ae Updated election_cycle init docstring.
build_develop / build (push) Successful in 1m24s
build_latest / build (push) Successful in 43s
2023-09-14 11:55:08 -04:00
imcompiling fb909c009a Quick bugfix for finding next election. Wouldn't happen in live, but better than hard coding. 2023-09-14 11:52:33 -04:00
imcompiling bdefa035ff Merge branch '25-cakeday'
build_latest / build (push) Successful in 44s
build_develop / build (push) Successful in 45s
build_release / build (push) Successful in 43s
2023-09-14 11:34:14 -04:00
imcompiling 85eb52d2e1 add word to message string.
build_develop / build (push) Successful in 1m31s
2023-09-14 11:33:27 -04:00
imcompiling 7d1b2f7cac Create cakedays function. 2023-09-14 11:24:25 -04:00
imcompiling c5c79015a9 Correct spelling. 2023-09-14 11:22:53 -04:00
imcompiling 7b335efbe6 Merge branch '22-daily-loop-not-starting-election'
build_latest / build (push) Successful in 44s
build_release / build (push) Successful in 43s
build_develop / build (push) Successful in 45s
2023-09-13 10:52:08 -04:00
imcompiling e686cf88e5 Be inclusive when checkign for an election cycle.
build_develop / build (push) Has been cancelled
2023-09-13 10:51:16 -04:00
imcompiling 117dea48c4 Standardize variable name of dates. 2023-09-13 10:42:01 -04:00
imcompiling 62e4417ce8 Use correct action on voting start. 2023-09-13 10:32:59 -04:00
imcompiling 672df41f19 Make the configs and timeline more clear. 2023-09-13 10:16:50 -04:00
imcompiling 328f3fea78 Merge branch 'main' into 22-daily-loop-not-starting-election 2023-09-13 09:31:53 -04:00
imcompiling 18751bc85c Inform Kandy when it is her "birthday".
build_release / build (push) Successful in 48s
build_latest / build (push) Successful in 43s
build_develop / build (push) Successful in 43s
2023-09-12 13:17:25 -04:00
imcompiling e243b40be7 Merge branch '19-birthday-tracking'
build_latest / build (push) Successful in 44s
build_develop / build (push) Successful in 42s
build_release / build (push) Successful in 42s
2023-09-09 13:48:36 -04:00
imcompiling 7a91cd37ec Add birthdays from database.
build_develop / build (push) Has been cancelled
2023-09-09 13:48:22 -04:00
imcompiling efadcb30c7 Finish up set birthday command. 2023-09-09 13:27:22 -04:00
imcompiling 1a8c5616ef Merge branch 'main' into 19-birthday-tracking
build_develop / build (push) Successful in 1m24s
2023-09-09 11:48:47 -04:00
imcompiling 0710db0654 Merge branch 'main' into 19-birthday-tracking
build_develop / build (push) Successful in 1m27s
2023-09-03 21:13:14 -04:00
imcompiling 077119acdd Add initial set birthday command. 2023-08-30 22:49:28 -04:00
imcompiling ac8d1bc681 Start update_birthdays function.
build_develop / build (push) Successful in 1m24s
2023-08-26 23:04:31 -04:00
imcompiling df8cb3dd49 Add message listener portion of birthday fun. 2023-08-26 22:52:02 -04:00
12 changed files with 242 additions and 38 deletions
+9 -3
View File
@@ -1,6 +1,10 @@
name: build_develop
on: [push]
on:
push:
branches:
- '*'
- '!main'
jobs:
build:
@@ -18,7 +22,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/dakiny-bot:develop .
run: docker build -t gitea.cheezers.org/imcompiling/dakiny-bot:${{env.GIT_BRANCH}} .
- name: Push Docker Image
run: docker push gitea.cheezers.org/imcompiling/dakiny-bot:develop
run: docker push gitea.cheezers.org/imcompiling/dakiny-bot:${{env.GIT_BRANCH}}
+8 -8
View File
@@ -34,16 +34,16 @@ The Clan Council will be denoted by the Discord ranks of <@&{clan_council_id}> a
<:Rank_Owner:479008325137072155> Clan Leader
---message_break---
__Here's the timeline:__
Election begins: {election_start_date}
Term: {term_start_date} - {term_end_date}
Election begins: {election_start}
Term: {term_start} - {term_end}
**{election_start_date}**: Post here to announce candidacy
**{voting_start_date}**: Voting begins
**{voting_end_date}**: Votes are tallied and winners are announced
**{highcouncil_election_date}**: The new Clan Council votes who among them shall receive the two High Council positions of: Clan Leader and Discord Server Manager.
**{term_start_date}**: The new Clan Council is officially inaugurated and a drop party (or a giveaway event) begins to commemorate the new leadership.
**{election_start}**: Post here to announce candidacy
**{voting_start}**: Voting begins
**{voting_end}**: Votes are tallied and winners are announced
**{highcouncil_election}**: The new Clan Council votes who among them shall receive the two High Council positions of: Clan Leader and Discord Server Manager.
**{term_start}**: The new Clan Council is officially inaugurated and a drop party (or a giveaway event) begins to commemorate the new leadership.
This process will begin again next quarter on {next_election_start_date} with the inauguration scheduled for {term_end_date}.
This process will begin again next quarter on {next_election_start} with the inauguration scheduled for {term_end}.
---message_break---
**You may now announce your candidacy for a seat on the Dakiny Clan Council!
**
+2 -2
View File
@@ -8,6 +8,6 @@ From {highcouncil_election_announce} to {highcouncil_election_start}, you will b
Discord Server Manager
Each member of the CCE can cast one for each category by using the emotes: <:Rank_Owner:479008325137072155> for Clan Leader and <:Rank_Deputy:479008295319896064> for Discord Server Manager.
If needed, the icon 🤷 can be used to abstain to vote in any or both categories and it should be apply to all candidates of that category.
If needed, the icon 🤷 can be used to abstain to vote in any or both categories and it should be applied to all candidates of that category.
Votes can be cast until the {highcouncil_election_end}, so we can announce and have everyone set up to start the term by {term_start}.
Votes can be cast until {highcouncil_election_end}, so we can announce and have everyone set up to start the term by {term_start}.
+1 -1
View File
@@ -2,7 +2,7 @@
<@&{clan_member_id}>, it's time to vote for clan council.
React with <{voting_emote_id}> to vote.
Voting ends next {voting_end_day}, {voting_end_date}.
Voting ends next {voting_end_day}, {voting_end}.
Results will then be announced.
After a candidate receives 3 votes, their spot is secured in the new council, but you can still vote for them to show your support.
+28 -22
View File
@@ -2,7 +2,7 @@
Contains the election cycle class
"""
from datetime import datetime, timedelta
from datetime import datetime
import nextcord
from sqlalchemy import select
@@ -21,14 +21,14 @@ class ElectionCycle:
def __init__(self, cycle: int, config: DakinyConfig, guild: nextcord.Guild) -> None:
"""
Generates all dates relevant to the election cycle from input election start, term start and end dates.
Generates all dates relevant to the election cycle determined by the config and cycle.
Args:
election_start (datetime): Date the election cycle starts.
term_start (datetime): Date the term being elected starts.
term_end (datetime): Date the term being elected ends.
bot: the discord bot instance
cycle (int): Which election cycle this cycle is.
config (DakinyConfig): The entire config object.
guild (nextcord.Guild): The guild that this election is running in.
"""
self.config: DakinyConfig = config
self.cycle = cycle
self.elecion_cycle = self.config.election_cycles[self.cycle]
@@ -37,9 +37,9 @@ class ElectionCycle:
self.term_end: datetime = get_datetime(self.elecion_cycle.term_end)
self.voting_start: datetime = get_datetime(self.elecion_cycle.voting_start)
self.voting_end: datetime = get_datetime(self.elecion_cycle.voting_end)
self.highcouncil_election_announce: datetime = self.voting_end + timedelta(days=1)
self.highcouncil_election_start: datetime = self.highcouncil_election_announce + timedelta(days=3)
self.highcouncil_election_end: datetime = self.term_start - timedelta(days=1)
self.highcouncil_election_announce: datetime = get_datetime(self.elecion_cycle.highcouncil_election_announce)
self.highcouncil_election_start: datetime = get_datetime(self.elecion_cycle.highcouncil_election_start)
self.highcouncil_election_end: datetime = get_datetime(self.elecion_cycle.highcouncil_election_end)
self.guild: nextcord.Guild = guild
self.election_over: bool = False
@@ -55,18 +55,20 @@ class ElectionCycle:
with open("bot_messages/election_announcement.txt", mode="r", encoding="utf8") as file:
message = file.read()
next_election = get_datetime(self.config.election_cycles[(self.cycle + 1) % 4].election_start)
next_election = get_datetime(
self.config.election_cycles[(self.cycle + 1) % len(self.config.election_cycles)].election_start
)
message = message.format(
clan_council_id=self.config.params.clan_council_role_id,
high_council_id=self.config.params.high_council_role_id,
election_start_date=self.election_start.strftime("%B %d"),
term_start_date=self.term_start.strftime("%B %d"),
term_end_date=self.term_end.strftime("%B %d"),
voting_start_date=self.voting_start.strftime("%B %d"),
voting_end_date=self.voting_end.strftime("%B %d"),
highcouncil_election_date=self.highcouncil_election_start.strftime("%B %d"),
next_election_start_date=next_election.strftime("%B %d"),
election_start=self.election_start.strftime("%B %d"),
term_start=self.term_start.strftime("%B %d"),
term_end=self.term_end.strftime("%B %d"),
voting_start=self.voting_start.strftime("%B %d"),
voting_end=self.voting_end.strftime("%B %d"),
highcouncil_election=self.highcouncil_election_start.strftime("%B %d"),
next_election_start=next_election.strftime("%B %d"),
)
return message.split("---message_break---")
@@ -87,7 +89,7 @@ class ElectionCycle:
highcouncil_election_announce=self.highcouncil_election_announce.strftime("%B %d"),
highcouncil_election_start=self.highcouncil_election_start.strftime("%B %d"),
highcouncil_election_end=self.highcouncil_election_end.strftime("%B %d"),
term_start_date=self.term_start.strftime("%B %d"),
term_start=self.term_start.strftime("%B %d"),
)
def build_highcouncil_vote_start(self) -> str:
@@ -103,7 +105,7 @@ class ElectionCycle:
return message.format(
clan_council_elect_role_id=self.config.params.clan_council_elect_role_id,
term_start_date=self.term_start.strftime("%B %d"),
term_start=self.term_start.strftime("%B %d"),
)
def build_vote_start(self) -> str:
@@ -121,7 +123,7 @@ class ElectionCycle:
return message.format(
clan_member_id=self.config.params.clan_member_role_id,
voting_emote_id=self.config.params.voting_emote_id,
voting_end_date=vote_end.strftime("%B %d"),
voting_end=vote_end.strftime("%B %d"),
voting_end_day=vote_end.strftime("%A"),
)
@@ -135,7 +137,7 @@ class ElectionCycle:
if today.date() == self.election_start.date():
await self.election_start_action()
elif today.date() == self.voting_start.date():
await self.voting_end_action()
await self.voting_start_action()
elif today.date() == self.voting_end.date():
await self.voting_end_action()
elif today.date() == self.highcouncil_election_start.date():
@@ -153,6 +155,8 @@ class ElectionCycle:
# create new entry into database.
election_channel: nextcord.TextChannel = await category.create_text_channel(quarter_name)
clan_member_role: nextcord.Role = self.guild.get_role(self.config.params.clan_member_role_id)
await election_channel.set_permissions(clan_member_role, send_messages=True, add_reactions=True)
with Session(engine) as session:
new_cycle = ElectionInformation(ElectionCycle=quarter_name, ElectionChannel=election_channel.id)
session.add(new_cycle)
@@ -184,8 +188,10 @@ class ElectionCycle:
message = self.build_highcouncil_election_announce()
council_elect_role: nextcord.Role = self.guild.get_role(self.config.params.clan_council_elect_role_id)
election_channel: nextcord.TextChannel = self.guild.get_channel(self.get_election_info().ElectionChannel)
clan_member_role: nextcord.Role = self.guild.get_role(self.config.params.clan_member_role_id)
await election_channel.send(message)
await election_channel.set_permissions(council_elect_role, send_messages=True)
await election_channel.set_permissions(council_elect_role, send_messages=True, add_reactions=True)
await election_channel.set_permissions(clan_member_role, add_reactions=False)
async def highcouncil_election_start_action(self) -> None:
"""
+3
View File
@@ -5,6 +5,7 @@ Cog loader. Adds all command cogs to the bot.
from nextcord.ext import commands
from cogs.commands.request import RequestCog
from cogs.commands.set import setCog
from cogs.commands.test import TestCog
@@ -14,5 +15,7 @@ def setup(bot: commands.Bot):
"""
Adds all command classes to bot.
"""
bot.add_cog(RequestCog(bot))
bot.add_cog(TestCog(bot))
bot.add_cog(setCog())
+85
View File
@@ -0,0 +1,85 @@
"""
Contains commands and views for set commands.
"""
from datetime import datetime
import nextcord
from nextcord.ext import commands
from sqlalchemy import delete, select
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import Session
from dakiny_bot import birthday_list
from database_setup.sql_data_classes import UserBirthday, engine
class setCog(commands.Cog, name="Set Commands"):
"""
Class holds set commands.
"""
def __init__(self) -> None:
"""
Default constructor for SetCog class. Does nothing.
"""
@nextcord.slash_command()
async def set(self, interaction: nextcord.Interaction):
"""
Parent slash command for set. Never called.
"""
@set.subcommand(description="Sets your birth month and day for the Birthday Fun. Use 0/0 to remove yourself.")
async def birthday(
self,
interaction: nextcord.Interaction,
month: int = nextcord.SlashOption(required=True, min_value=0, max_value=12, description="Your birth month."),
day: int = nextcord.SlashOption(required=True, min_value=0, max_value=31, description="Your birth day."),
):
"""
Sets a user's birthday in the database. Removes on input 0/0. If birthday is today, adds to the birthday_list.
Args:
interaction (nextcord.Interaction): Interaction that invoked the command.
month (int, optional): The month a user was born. Is SlashOption.
day (int, optional): The day a user was born. Is SlashOption.
"""
# Must be deferred, apparently datetime takes a little bit on invalid dates.
await interaction.response.defer(ephemeral=True)
if month == 0 and day == 0:
stmt = delete(UserBirthday).where(UserBirthday.UserId == interaction.user.id)
with Session(engine) as session:
session.execute(stmt)
session.commit()
await interaction.followup.send("Removed birthday.", ephemeral=True)
return
# check if valid day
today = datetime.today()
try:
birthday = datetime(today.year, month, day)
except ValueError:
await interaction.followup.send(f"Invalid date: {month}/{day}.", ephemeral=True)
return
# If the birthday is today, add to birthday_list
if today.date() == birthday.date():
birthday_list.append(interaction.user.id)
new_birthday = UserBirthday(UserId=interaction.user.id, Birthday=f"{month}/{day}")
with Session(engine) as session:
try:
session.add(new_birthday)
session.commit()
except IntegrityError:
# User already has birthday, change it instead.
session.rollback()
stmt = select(UserBirthday).where(UserBirthday.UserId == interaction.user.id)
new_birthday = session.scalar(stmt)
new_birthday.Birthday = f"{month}/{day}"
session.commit()
await interaction.followup.send(f"Birthday set to {month}/{day}.", ephemeral=True)
+55 -1
View File
@@ -2,13 +2,19 @@
Defines the daily loop that runs the Dakiny bot functions.
"""
import random
from datetime import datetime, time
import nextcord
from nextcord.ext import commands, tasks
from pytz import timezone
from sqlalchemy import select
from sqlalchemy.orm import Session
from classes.election_cycle import ElectionCycle
from config import DakinyConfig
from dakiny_bot import birthday_list
from database_setup.sql_data_classes import UserBirthday, engine
from utils import get_datetime
@@ -20,6 +26,7 @@ class DailyLoop(commands.Cog, name="Daily Loop"):
def __init__(self, bot: commands.Bot) -> None:
self.bot = bot
self.current_election = None
self.update_birthdays()
# pylint doesn't recognize that daily_loop is subclassed from tasks.loop.
self.daily_loop.start() # pylint: disable=no-member
@@ -40,6 +47,15 @@ class DailyLoop(commands.Cog, name="Daily Loop"):
if self.current_election.election_over:
self.current_election = None
self.update_birthdays()
if 239547993106284544 in birthday_list:
# inform kandy that it is her "birthday"
kandy: nextcord.User = await self.bot.fetch_user(239547993106284544)
await kandy.send('Happy "Birthday"!')
await self.cakedays()
@daily_loop.before_loop
async def before_loop(self):
"""
@@ -67,8 +83,46 @@ class DailyLoop(commands.Cog, name="Daily Loop"):
for cycle, election in enumerate(config.election_cycles):
if (
today.date() >= get_datetime(election.election_start).date()
and today.date() < get_datetime(election.term_start).date()
and today.date() <= get_datetime(election.term_start).date()
):
current_election = ElectionCycle(cycle, config, self.bot.get_guild(config.params.guild_id))
return current_election
def update_birthdays(self) -> None:
"""
Goes through database to collect all birthdays that are today. Adds user's id to birthday list.
"""
birthday_list.clear()
# kandy's 1% chance
if random.randint(0, 99) == 0:
birthday_list.append(239547993106284544)
today = datetime.today()
birthday = f"{today.month}/{today.day}"
stmt = select(UserBirthday.UserId).where(UserBirthday.Birthday == birthday)
with Session(engine) as session:
to_add = session.scalars(stmt)
birthday_list.extend(to_add.all())
async def cakedays(self) -> None:
"""
Loops through the guild's humans checking for joined_at dates that match today's date. Sends a message
saying happy cakeday.
"""
today = datetime.today()
guild: nextcord.Guild = self.bot.get_guild(self.bot.config.params.guild_id)
announce_channel: nextcord.TextChannel = guild.get_channel(self.bot.config.params.general_channel_id)
cakedays: list[nextcord.Member] = [
human for human in guild.humans if human.joined_at.month == today.month and human.joined_at.day == today.day
]
for member in cakedays:
years = today.year - member.joined_at.year
year_str = "years" if years > 1 else "year"
msg = f"Happy Cake day! <@{member.id}> joined the discord {years} {year_str} ago!"
await announce_channel.send(msg)
+43
View File
@@ -0,0 +1,43 @@
"""
Defines cog for on message listener.
"""
import nextcord
from nextcord.ext import commands
from dakiny_bot import birthday_list
class SubmissionListener(commands.Cog, name="Message Listener"):
"""Sets up message listener."""
def __init__(self, bot: commands.Bot):
self.bot = bot
@commands.Cog.listener()
async def on_message(self, message: nextcord.Message):
"""Listener for message creation. Adds score and attachments to submission."""
# don't want to process any messages from bot.
if message.author.id == self.bot.user.id:
return
await birthday_action(message)
# This function will be called when this extension is loaded.
# It is necessary to add these functions to the bot.
def setup(bot: commands.Bot):
"""Adds function to bot"""
bot.add_cog(SubmissionListener(bot))
async def birthday_action(message: nextcord.Message) -> None:
"""
Checks a message's auther and mentions to see if they are in the birthday list.
Args:
message (nextcord.Message): The message to check for a birthday person.
"""
if message.author.id in birthday_list or bool(set(message.raw_mentions) & set(birthday_list)):
await message.add_reaction("🎂")
+5 -1
View File
@@ -12,13 +12,14 @@ class Params:
active_category_id: int
admin_channel_id: int # might want to rename this...
annoucement_category_id: int
announcement_category_id: int
archive_channel_group_id: int
clan_council_elect_role_id: int
clan_council_role_id: int
clan_info_channel_id: int
clan_member_role_id: int
discord_token: str
general_channel_id: int
guild_id: int
high_council_role_id: int
voting_emote_id: str
@@ -31,6 +32,9 @@ class ElectionCycle:
"""
election_start: str
highcouncil_election_announce: str
highcouncil_election_end: str
highcouncil_election_start: str
name: str
term_end: str
term_start: str
+2
View File
@@ -13,6 +13,8 @@ from config import DakinyConfig
cs = ConfigStore.instance()
cs.store(name="dakiny_config", node=DakinyConfig)
birthday_list: list[int] = []
logger = logging.getLogger("nextcord")
logger.setLevel(logging.DEBUG)
handler = logging.FileHandler(filename="nextcord.log", encoding="utf-8", mode="w")
+1
View File
@@ -14,3 +14,4 @@ Base.prepare(autoload_with=engine)
ElectionInformation = Base.classes.ElectionInformation
CouncilMembers = Base.classes.CouncilMembers
Votes = Base.classes.Votes
UserBirthday = Base.classes.UserBirthday