diff --git a/DakinySettings.py b/DakinySettings.py new file mode 100644 index 0000000..0bdf017 --- /dev/null +++ b/DakinySettings.py @@ -0,0 +1,82 @@ +"""File contains classes defining Dakiny settings structure.""" + +from dataclasses import dataclass + +from dataclass_wizard import YAMLWizard + +CONFIG_LOCATION = "conf/config.yaml" + + +@dataclass +class ChannelIds: + """Class holds all channel ids needed by bot.""" + + admin: int # might want to rename this... + announcement_category: int + clan_info: int + event_post: int + general: int + voting_parent: int + + +@dataclass +class Election: + """Class defines relevant election dates.""" + + name: str + election_start: str + highcouncil_election_announce: str + highcouncil_election_end: str + highcouncil_election_start: str + term_end: str + term_start: str + voting_end: str + voting_start: str + + +@dataclass +class Params: + """Class defines start parameters that shouldn't be changed.""" + + discord_token: str + git_branch: str + guild_id: int + + +@dataclass +class RoleIds: + """Class holds all role ids needed by bot.""" + + clan_council_elect: int + clan_council: int + clan_member: int + event_host: int + high_council: int + + +@dataclass +class EventSettings: + """Class defines settings editable by Clan Council.""" + + host_points: int + participate_points: int + weekly_limit: int + + +@dataclass +class DakinySettings(YAMLWizard): + """Class defines all configs required for Dakiny Bot.""" + + channel_ids: ChannelIds + election_cycles: list[Election] + event_settings: EventSettings + params: Params + role_ids: RoleIds + + def save(self) -> None: + """Saves settings to the yaml file.""" + self.to_yaml_file(CONFIG_LOCATION) + + +settings = DakinySettings.from_yaml_file(CONFIG_LOCATION) +settings.save() diff --git a/Dockerfile b/Dockerfile index 8abedd6..094b885 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ RUN apt-get update && apt-get -y upgrade && apt-get -y install git sqlite3 WORKDIR /home -COPY config.py config.py +COPY DakinySettings.py DakinySettings.py COPY main.py main.py COPY utils.py utils.py COPY pyproject.toml pyproject.toml diff --git a/classes/election.py b/classes/election.py index 6ff2011..8a3995b 100644 --- a/classes/election.py +++ b/classes/election.py @@ -9,7 +9,7 @@ from classes.nominate_highcouncil_views import NominateHighCouncilView from classes.nominate_views import NominateView from classes.voting_highcouncil_views import VoteHighcouncilView from classes.voting_views import VoteView -from config import DakinyConfig +from DakinySettings import settings from database_setup.sql_data_classes import ( CouncilMembers, ElectionInformation, @@ -39,18 +39,16 @@ class Election: the cycle. """ - def __init__(self, cycle: int, config: DakinyConfig, guild: nextcord.Guild) -> None: + def __init__(self, cycle: int, guild: nextcord.Guild) -> None: """ Generates all dates relevant to the election cycle determined by the config and cycle. Args: 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.election_cycle = self.config.election_cycles[self.cycle] + self.election_cycle = settings.election_cycles[self.cycle] self.election_start: datetime = get_datetime(self.election_cycle.election_start) self.term_start: datetime = get_datetime(self.election_cycle.term_start) self.term_end: datetime = get_datetime(self.election_cycle.term_end) @@ -74,12 +72,12 @@ class Election: message = file.read() next_election = get_datetime( - self.config.election_cycles[(self.cycle + 1) % len(self.config.election_cycles)].election_start + settings.election_cycles[(self.cycle + 1) % len(settings.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, + clan_council_id=settings.role_ids.clan_council, + high_council_id=settings.role_ids.high_council, election_start=self.election_start.strftime("%B %d"), term_start=self.term_start.strftime("%B %d"), term_end=self.term_end.strftime("%B %d"), @@ -102,7 +100,7 @@ class Election: message = file.read() return message.format( - clan_council_elect_role_id=self.config.params.clan_council_elect_role_id, + clan_council_elect_role_id=settings.role_ids.clan_council_elect, 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"), @@ -120,7 +118,7 @@ class Election: message = file.read() return message.format( - clan_council_elect_role_id=self.config.params.clan_council_elect_role_id, + clan_council_elect_role_id=settings.role_ids.clan_council_elect, term_start=self.term_start.strftime("%B %d"), ) @@ -133,10 +131,10 @@ class Election: """ with Path(f"{TEMPLATES_DIR}/vote_start.txt", encoding="utf8").open() as file: message = file.read() - vote_end: datetime = get_datetime(self.config.election_cycles[self.cycle].voting_end) + vote_end: datetime = get_datetime(settings.election_cycles[self.cycle].voting_end) return message.format( - clan_member_id=self.config.params.clan_member_role_id, + clan_member_id=settings.role_ids.clan_member, voting_end=vote_end.strftime("%B %d"), voting_end_day=vote_end.strftime("%A"), ) @@ -162,8 +160,8 @@ class Election: async def election_start_action(self) -> None: """Performs required actions for when the election cycle starts.""" # create new channel for election - parent: nextcord.TextChannel = self.guild.get_channel(self.config.params.voting_parent_id) - quarter_name: str = get_election_name(self.config) + parent: nextcord.TextChannel = self.guild.get_channel(settings.channel_ids.voting_parent) + quarter_name: str = get_election_name() thread_msg: nextcord.Message = await parent.send(content=quarter_name) @@ -176,7 +174,7 @@ class Election: for index, message in enumerate(messages): # if last item, add the nominate button if index + 1 == len(messages): - nominate_msg: nextcord.Message = await thread.send(message, view=NominateView(self.config, self.guild)) + nominate_msg: nextcord.Message = await thread.send(message, view=NominateView(self.guild)) else: await thread.send(message) @@ -201,12 +199,12 @@ class Election: election_thread: nextcord.Thread = self.guild.get_thread(self.get_election_info().ThreadId) await election_thread.send(message) vote_msg = await election_thread.send( - build_votes_str(self.config, self.guild), - view=VoteView(self.config, self.guild), + build_votes_str(settings, self.guild), + view=VoteView(self.guild), ) with Session(engine) as session: - stmt = select(ElectionInformation).where(ElectionInformation.ElectionName == get_election_name(self.config)) + stmt = select(ElectionInformation).where(ElectionInformation.ElectionName == get_election_name()) info = session.scalar(stmt) info.CouncilVoteMsgId = vote_msg.id session.commit() @@ -218,14 +216,12 @@ class Election: async def voting_end_action(self) -> None: """Performs required actions for when voting time has ended.""" message = self.build_highcouncil_election_announce() - council_elect_role: nextcord.Role = self.guild.get_role(self.config.params.clan_council_elect_role_id) + council_elect_role: nextcord.Role = self.guild.get_role(settings.role_ids.clan_council_elect) election_thread: nextcord.Thread = self.guild.get_thread(self.get_election_info().ThreadId) - nominate_msg: nextcord.Message = await election_thread.send( - message, view=NominateHighCouncilView(self.config, self.guild) - ) + nominate_msg: nextcord.Message = await election_thread.send(message, view=NominateHighCouncilView(self.guild)) - election_name = get_election_name(self.config) + election_name = get_election_name() with Session(engine) as session: # remove vote button from vote message @@ -270,12 +266,12 @@ class Election: election_thread: nextcord.Thread = self.guild.get_thread(self.get_election_info().ThreadId) await election_thread.send(message) vote_msg = await election_thread.send( - build_highcouncil_votes_str(self.config, self.guild), - view=VoteHighcouncilView(self.config, self.guild), + build_highcouncil_votes_str(self.guild), + view=VoteHighcouncilView(self.guild), ) with Session(engine) as session: - stmt = select(ElectionInformation).where(ElectionInformation.ElectionName == get_election_name(self.config)) + stmt = select(ElectionInformation).where(ElectionInformation.ElectionName == get_election_name()) info = session.scalar(stmt) info.HighCouncilVoteMsgId = vote_msg.id session.commit() @@ -288,10 +284,10 @@ class Election: """Marks the election as over.""" self.election_over = True - elect_role: nextcord.Role = self.guild.get_role(self.config.params.clan_council_elect_role_id) - council_role: nextcord.Role = self.guild.get_role(self.config.params.clan_council_role_id) + elect_role: nextcord.Role = self.guild.get_role(settings.role_ids.clan_council_elect) + council_role: nextcord.Role = self.guild.get_role(settings.role_ids.clan_council) - election_name = get_election_name(self.config) + election_name = get_election_name() with Session(engine) as session: # role management @@ -356,7 +352,7 @@ class Election: # clear view from vote message stmt = select(ElectionInformation.HighCouncilVoteMsgId).where( - ElectionInformation.ElectionName == get_election_name(self.config) + ElectionInformation.ElectionName == get_election_name() ) vote_msg_id = session.scalar(stmt) vote_msg: nextcord.Message = await election_thread.fetch_message(vote_msg_id) @@ -369,7 +365,7 @@ class Election: await election_thread.send("This election cycle is now over. Thank you everyone for participating!") await election_thread.edit(archived=True, locked=True) - await edit_clan_council_info(self.guild, self.config) + await edit_clan_council_info(self.guild) def get_election_info(self) -> ElectionInformation: """ @@ -379,14 +375,14 @@ class Election: ElectionInformation: The information from the database about the current election. """ with Session(engine) as session: - stmt = select(ElectionInformation).where(ElectionInformation.ElectionName == get_election_name(self.config)) + stmt = select(ElectionInformation).where(ElectionInformation.ElectionName == get_election_name()) return session.scalar(stmt) async def election_reminder(self) -> None: """Sends a message to general chat reminder clan about election.""" - general: nextcord.TextChannel = self.guild.get_channel(self.config.params.general_channel_id) + general: nextcord.TextChannel = self.guild.get_channel(settings.channel_ids.general) - message = f"Reminder to <@&{self.config.params.clan_member_role_id}>! Clan elections are happening! Head over " + message = f"Reminder to <@&{settings.role_ids.clan_member}>! Clan elections are happening! Head over " message += f"to <#{self.get_election_info().ThreadId}> to cast your vote!" await general.send(content=message) diff --git a/classes/nominate_highcouncil_views.py b/classes/nominate_highcouncil_views.py index 620bde9..e461ac1 100644 --- a/classes/nominate_highcouncil_views.py +++ b/classes/nominate_highcouncil_views.py @@ -1,7 +1,7 @@ """Contains various views to be used in the high council nomination process.""" import nextcord -from config import DakinyConfig +from DakinySettings import settings from database_setup.sql_data_classes import CouncilMembers, engine from nextcord.interactions import Interaction from sqlalchemy import select @@ -23,7 +23,6 @@ class NominateDMModal(nextcord.ui.Modal): def __init__( self, - config: DakinyConfig, usr_id: int, usr_nominated: bool, # noqa: FBT001 speech_content: str, @@ -33,7 +32,6 @@ class NominateDMModal(nextcord.ui.Modal): timeout=5 * 60, # 5 minutes ) self.usr_id: int = usr_id - self.config: DakinyConfig = config self.usr_nominated = usr_nominated self.speech = nextcord.ui.TextInput( @@ -58,7 +56,7 @@ class NominateDMModal(nextcord.ui.Modal): with Session(engine) as session: # user already in table - election_name = get_election_name(self.config) + election_name = get_election_name() stmt = ( select(CouncilMembers) .where(CouncilMembers.ElectionName == election_name) @@ -85,7 +83,6 @@ class NominateCLModal(nextcord.ui.Modal): def __init__( self, - config: DakinyConfig, usr_id: int, usr_nominated: bool, # noqa: FBT001 speech_content: str, @@ -95,7 +92,6 @@ class NominateCLModal(nextcord.ui.Modal): timeout=5 * 60, # 5 minutes ) self.usr_id: int = usr_id - self.config: DakinyConfig = config self.usr_nominated = usr_nominated self.speech = nextcord.ui.TextInput( @@ -120,7 +116,7 @@ class NominateCLModal(nextcord.ui.Modal): with Session(engine) as session: # user already in table - election_name = get_election_name(self.config) + election_name = get_election_name() stmt = ( select(CouncilMembers) .where(CouncilMembers.ElectionName == election_name) @@ -141,9 +137,8 @@ class NominateCLModal(nextcord.ui.Modal): class NominateHighCouncilView(nextcord.ui.View): """The buttons to press to start your High Council nomination.""" - def __init__(self, config: DakinyConfig, guild: nextcord.Guild): + def __init__(self, guild: nextcord.Guild): super().__init__(timeout=None) - self.config: DakinyConfig = config self.guild: nextcord.Guild = guild @nextcord.ui.button( @@ -163,14 +158,14 @@ class NominateHighCouncilView(nextcord.ui.View): interaction (nextcord.Interaction): Interaction of user who pressed the button """ # enforce council elect only - if self.guild.get_role(self.config.params.clan_council_elect_role_id) not in interaction.user.roles: + if self.guild.get_role(settings.role_ids.clan_council_elect) not in interaction.user.roles: await interaction.response.send_message( - f"You must have the <@&{self.config.params.clan_council_elect_role_id}> role to vote.", + f"You must have the <@&{settings.role_ids.clan_council_elect}> role to vote.", ephemeral=True, ) return - election_name = get_election_name(self.config) + election_name = get_election_name() usr_nominated = False speech_content = "" with Session(engine) as session: @@ -187,9 +182,7 @@ class NominateHighCouncilView(nextcord.ui.View): msg = await interaction.channel.fetch_message(obj.DiscordManagerSpeechId) speech_content = msg.content.split(NOMINEE_SPLITTER)[1] - await interaction.response.send_modal( - NominateDMModal(self.config, interaction.user.id, usr_nominated, speech_content) - ) + await interaction.response.send_modal(NominateDMModal(interaction.user.id, usr_nominated, speech_content)) @nextcord.ui.button( label="Nominate for Clan Leader", @@ -208,14 +201,14 @@ class NominateHighCouncilView(nextcord.ui.View): interaction (nextcord.Interaction): Interaction of user who pressed the button """ # enforce council elect only - if self.guild.get_role(self.config.params.clan_council_elect_role_id) not in interaction.user.roles: + if self.guild.get_role(settings.role_ids.clan_council_elect) not in interaction.user.roles: await interaction.response.send_message( - f"You must have the <@&{self.config.params.clan_council_elect_role_id}> role to vote.", + f"You must have the <@&{settings.role_ids.clan_council_elect}> role to vote.", ephemeral=True, ) return - election_name = get_election_name(self.config) + election_name = get_election_name() usr_nominated = False speech_content = "" with Session(engine) as session: @@ -232,6 +225,4 @@ class NominateHighCouncilView(nextcord.ui.View): msg = await interaction.channel.fetch_message(obj.ClanLeaderSpeechId) speech_content = msg.content.split(NOMINEE_SPLITTER)[1] - await interaction.response.send_modal( - NominateCLModal(self.config, interaction.user.id, usr_nominated, speech_content) - ) + await interaction.response.send_modal(NominateCLModal(interaction.user.id, usr_nominated, speech_content)) diff --git a/classes/nominate_views.py b/classes/nominate_views.py index f704420..3f7858a 100644 --- a/classes/nominate_views.py +++ b/classes/nominate_views.py @@ -1,7 +1,7 @@ """Contains various views to be used in the nomination process.""" import nextcord -from config import DakinyConfig +from DakinySettings import settings from database_setup.sql_data_classes import CouncilMembers, engine from nextcord.interactions import Interaction from sqlalchemy import select @@ -18,7 +18,6 @@ class NominateModal(nextcord.ui.Modal): def __init__( self, - config: DakinyConfig, usr_id: int, usr_nominated: bool, # noqa: FBT001 speech_content: str, @@ -28,7 +27,6 @@ class NominateModal(nextcord.ui.Modal): timeout=5 * 60, # 5 minutes ) self.usr_id: int = usr_id - self.config: DakinyConfig = config self.usr_nominated = usr_nominated self.speech = nextcord.ui.TextInput( @@ -50,7 +48,7 @@ class NominateModal(nextcord.ui.Modal): """ speech = decorate_nomination(interaction.user.id, self.speech.value) - election_name = get_election_name(self.config) + election_name = get_election_name() with Session(engine) as session: if not self.usr_nominated: @@ -79,9 +77,8 @@ class NominateModal(nextcord.ui.Modal): class NominateView(nextcord.ui.View): """The button to press to start your nomination.""" - def __init__(self, config: DakinyConfig, guild: nextcord.Guild): + def __init__(self, guild: nextcord.Guild): super().__init__(timeout=None) - self.config: DakinyConfig = config self.guild: nextcord.Guild = guild @nextcord.ui.button( @@ -101,14 +98,14 @@ class NominateView(nextcord.ui.View): interaction (nextcord.Interaction): Interaction of user who pressed the button """ # enforce members only - if self.guild.get_role(self.config.params.clan_member_role_id) not in interaction.user.roles: + if self.guild.get_role(settings.role_ids.clan_member) not in interaction.user.roles: await interaction.response.send_message( - f"You must have the <@&{self.config.params.clan_member_role_id}> role to vote.", + f"You must have the <@&{settings.role_ids.clan_member}> role to vote.", ephemeral=True, ) return - election_name = get_election_name(self.config) + election_name = get_election_name() usr_nominated = False speech_content = "" with Session(engine) as session: @@ -123,6 +120,4 @@ class NominateView(nextcord.ui.View): msg = await interaction.channel.fetch_message(obj.SpeechMsgId) speech_content = msg.content.split(NOMINEE_SPLITTER)[1] - await interaction.response.send_modal( - NominateModal(self.config, interaction.user.id, usr_nominated, speech_content) - ) + await interaction.response.send_modal(NominateModal(interaction.user.id, usr_nominated, speech_content)) diff --git a/classes/voting_highcouncil_views.py b/classes/voting_highcouncil_views.py index e3497b2..9ccd3ca 100644 --- a/classes/voting_highcouncil_views.py +++ b/classes/voting_highcouncil_views.py @@ -1,7 +1,7 @@ """Contains various views to be used while voting for high council. Controls the logic when performing the vote.""" import nextcord -from config import DakinyConfig +from DakinySettings import settings from database_setup.sql_data_classes import ( CouncilMembers, ElectionInformation, @@ -18,14 +18,13 @@ from utils import VoteType, build_highcouncil_votes_str, get_election_name class VoteSelect(nextcord.ui.StringSelect): """Vote view string select.""" - def __init__(self, options: list["SelectOption"], config: DakinyConfig, election_type: str) -> None: + def __init__(self, options: list["SelectOption"], election_type: str) -> None: super().__init__( placeholder="Choose 1", min_values=1, max_values=1, options=options, ) - self.config = config self.election_type = election_type async def callback(self, interaction: Interaction) -> None: @@ -38,7 +37,7 @@ class VoteSelect(nextcord.ui.StringSelect): Args: interaction (Interaction): Interaction with this callback. """ - election_name: str = get_election_name(self.config) + election_name: str = get_election_name() with Session(engine) as session: stmt = select(ElectionInformation.HighCouncilVoteMsgId).where( ElectionInformation.ElectionName == election_name @@ -71,7 +70,7 @@ class VoteSelect(nextcord.ui.StringSelect): session.execute(stmt) session.commit() - vote_message_str = build_highcouncil_votes_str(self.config, interaction.guild) + vote_message_str = build_highcouncil_votes_str(interaction.guild) vote_msg: nextcord.Message = await interaction.channel.fetch_message(vote_msg_id) await vote_msg.edit(content=vote_message_str) @@ -83,9 +82,8 @@ class VoteSelect(nextcord.ui.StringSelect): class VoteHighcouncilView(nextcord.ui.View): """The button to press to start voting for HighCouncil.""" - def __init__(self, config: DakinyConfig, guild: nextcord.Guild): + def __init__(self, guild: nextcord.Guild): super().__init__(timeout=None) - self.config = config self.guild = guild @nextcord.ui.button( @@ -106,14 +104,14 @@ class VoteHighcouncilView(nextcord.ui.View): interaction (nextcord.Interaction): Interaction of user who pressed the button """ # enforce council elect only - if self.guild.get_role(self.config.params.clan_council_elect_role_id) not in interaction.user.roles: + if self.guild.get_role(settings.role_ids.clan_council_elect) not in interaction.user.roles: await interaction.response.send_message( - f"You must have the <@&{self.config.params.clan_council_elect_role_id}> role to vote.", + f"You must have the <@&{settings.role_ids.clan_council_elect}> role to vote.", ephemeral=True, ) return - election_name: str = get_election_name(self.config) + election_name: str = get_election_name() with Session(engine) as session: stmt = ( @@ -152,7 +150,7 @@ class VoteHighcouncilView(nextcord.ui.View): ) view = nextcord.ui.View() - view.add_item(VoteSelect(options=options, config=self.config, election_type=VoteType.CLANLEADER)) + view.add_item(VoteSelect(options=options, election_type=VoteType.CLANLEADER)) await interaction.response.send_message( content="Please vote for a Clan Leader!", @@ -178,14 +176,14 @@ class VoteHighcouncilView(nextcord.ui.View): interaction (nextcord.Interaction): Interaction of user who pressed the button """ # enforce council elect only - if self.guild.get_role(self.config.params.clan_council_elect_role_id) not in interaction.user.roles: + if self.guild.get_role(settings.role_ids.clan_council_elect) not in interaction.user.roles: await interaction.response.send_message( - f"You must have the <@&{self.config.params.clan_council_elect_role_id}> role to vote.", + f"You must have the <@&{settings.role_ids.clan_council_elect}> role to vote.", ephemeral=True, ) return - election_name: str = get_election_name(self.config) + election_name: str = get_election_name() with Session(engine) as session: stmt = ( @@ -227,7 +225,6 @@ class VoteHighcouncilView(nextcord.ui.View): view.add_item( VoteSelect( options=options, - config=self.config, election_type=VoteType.DISCORDMANAGER, ) ) diff --git a/classes/voting_views.py b/classes/voting_views.py index 4a51238..1ee91fe 100644 --- a/classes/voting_views.py +++ b/classes/voting_views.py @@ -1,7 +1,7 @@ """Contains various views to be used while voting. Controls the logic when performing the vote.""" import nextcord -from config import DakinyConfig +from DakinySettings import settings from database_setup.sql_data_classes import ( CouncilMembers, ElectionInformation, @@ -18,14 +18,13 @@ from utils import VoteType, build_votes_str, get_election_name class VoteSelect(nextcord.ui.StringSelect): """Vote view string select.""" - def __init__(self, options: list["SelectOption"], config: DakinyConfig) -> None: + def __init__(self, options: list["SelectOption"]) -> None: super().__init__( placeholder="Choose 1", min_values=1, max_values=1, options=options, ) - self.config = config async def callback(self, interaction: Interaction) -> None: """ @@ -37,7 +36,7 @@ class VoteSelect(nextcord.ui.StringSelect): Args: interaction (Interaction): Interaction with this callback. """ - election_name = get_election_name(self.config) + election_name = get_election_name() with Session(engine) as session: stmt = select(ElectionInformation.CouncilVoteMsgId).where(ElectionInformation.ElectionName == election_name) vote_msg_id = session.scalar(stmt) @@ -67,7 +66,7 @@ class VoteSelect(nextcord.ui.StringSelect): session.execute(stmt) session.commit() - vote_message_str = build_votes_str(self.config, interaction.guild) + vote_message_str = build_votes_str(settings, interaction.guild) vote_msg: nextcord.Message = await interaction.channel.fetch_message(vote_msg_id) await vote_msg.edit(content=vote_message_str) @@ -79,9 +78,8 @@ class VoteSelect(nextcord.ui.StringSelect): class VoteView(nextcord.ui.View): """The button to press to start your nomination.""" - def __init__(self, config: DakinyConfig, guild: nextcord.Guild): + def __init__(self, guild: nextcord.Guild): super().__init__(timeout=None) - self.config = config self.guild = guild @nextcord.ui.button(label="Vote", style=nextcord.ButtonStyle.primary, custom_id="vote") @@ -97,14 +95,14 @@ class VoteView(nextcord.ui.View): interaction (nextcord.Interaction): Interaction of user who pressed the button """ # enforce members only - if self.guild.get_role(self.config.params.clan_member_role_id) not in interaction.user.roles: + if self.guild.get_role(settings.role_ids.clan_member) not in interaction.user.roles: await interaction.response.send_message( - f"You must have the <@&{self.config.params.clan_member_role_id}> role to vote.", + f"You must have the <@&{settings.role_ids.clan_member}> role to vote.", ephemeral=True, ) return - election_name: str = get_election_name(self.config) + election_name: str = get_election_name() with Session(engine) as session: stmt = ( @@ -139,7 +137,7 @@ class VoteView(nextcord.ui.View): ) view = nextcord.ui.View() - view.add_item(VoteSelect(options=options, config=self.config)) + view.add_item(VoteSelect(options)) await interaction.response.send_message( content="Please vote for a clan member!", diff --git a/cogs/clan_messages/__init__.py b/cogs/clan_messages/__init__.py index 5e3d480..63fdd0d 100644 --- a/cogs/clan_messages/__init__.py +++ b/cogs/clan_messages/__init__.py @@ -9,13 +9,12 @@ from git import Repo from nextcord.ext import commands from classes.gitea_webhook import GiteaWebhook +from DakinySettings import settings from utils import REPO_DIR, edit_clan_council_info, update_clan_messages if TYPE_CHECKING: import nextcord - from config import DakinyConfig - app = FastAPI() REPO_URL = "https://gitea.cheezers.org/imcompiling/dakiny-messages.git" @@ -30,7 +29,6 @@ class ClanMessages(commands.Cog, name="Clan Messages"): def __init__(self, bot: commands.Bot): self.bot = bot - self.config: DakinyConfig = self.bot.config self.repo_setup() @commands.Cog.listener() @@ -58,13 +56,13 @@ class ClanMessages(commands.Cog, name="Clan Messages"): channel_updates = {file.split("/")[1] for file in modified_files if file.split("/")[1] not in template_updates} self.origin.pull() - guild: nextcord.Guild = self.bot.get_guild(self.config.params.guild_id) + guild: nextcord.Guild = self.bot.get_guild(settings.params.guild_id) await update_clan_messages(guild, channel_updates) # if the council members template has changed, update the message if "council_members.txt" in template_updates: - await edit_clan_council_info(self.bot.get_guild(self.config.params.guild_id), self.config) + await edit_clan_council_info(self.bot.get_guild(settings.params.guild_id)) return {"message": "Successfully updated all discord messages."} @@ -78,7 +76,7 @@ class ClanMessages(commands.Cog, name="Clan Messages"): self.origin = self.repo.remote("origin") - if self.config.params.git_branch == "test": + if settings.params.git_branch == "test": self.repo.create_head("test", self.origin.refs.test).set_tracking_branch(self.origin.refs.test).checkout() else: self.repo.create_head("main", self.origin.refs.main).set_tracking_branch(self.origin.refs.main).checkout() diff --git a/cogs/commands/record.py b/cogs/commands/record.py index 1aad3b7..eb7b877 100644 --- a/cogs/commands/record.py +++ b/cogs/commands/record.py @@ -4,7 +4,7 @@ import nextcord from discord import TextInputStyle from nextcord.ext import commands -from config import DakinyConfig +from DakinySettings import settings from utils import GUILDS, MAX_DISCORD_MESSAGE_LENGTH, record_event_points @@ -42,9 +42,9 @@ class RecordCog(commands.Cog, name="Record Commands"): host (nextcord.Member, optional): Alternative host to user using command. """ # check role - if interaction.guild.get_role(self.bot.config.params.event_host_role_id) not in interaction.user.roles: + if interaction.guild.get_role(settings.role_ids.event_host) not in interaction.user.roles: await interaction.response.send_message( - f"You must have the <@&{self.bot.config.params.event_host_role_id}> role to record an event.", + f"You must have the <@&{settings.role_ids.event_host}> role to record an event.", ephemeral=True, ) return @@ -59,7 +59,7 @@ class RecordCog(commands.Cog, name="Record Commands"): await interaction.response.send_message( "Fill out event details and select all members who participated!", - view=EventView(name, self.bot.config, host.id), + view=EventView(name, host.id), ephemeral=True, embed=embed, ) @@ -105,9 +105,9 @@ class RecordCog(commands.Cog, name="Record Commands"): non_discord_recipient (str): Non Discord member to give point to. """ # role check - if interaction.guild.get_role(self.bot.config.params.clan_member_role_id) not in interaction.user.roles: + if interaction.guild.get_role(settings.role_ids.clan_member) not in interaction.user.roles: await interaction.response.send_message( - f"You must have the <@&{self.bot.config.params.clan_member_role_id}> role to record points.", + f"You must have the <@&{settings.role_ids.clan_member}> role to record points.", ephemeral=True, ) return @@ -118,17 +118,15 @@ class RecordCog(commands.Cog, name="Record Commands"): return elif recipient is not None: # noqa: RET505 record_event_points( - self.bot.config, [str(recipient.id)], - self.bot.config.params.event_participate_points, + settings.event_settings.participate_points, is_member=True, ) recipient_str = f"<@{recipient.id}>" elif non_discord_recipient is not None: record_event_points( - self.bot.config, [non_discord_recipient], - self.bot.config.params.event_participate_points, + settings.event_settings.participate_points, is_member=False, ) recipient_str = f'"{non_discord_recipient}"' @@ -136,9 +134,7 @@ class RecordCog(commands.Cog, name="Record Commands"): await interaction.response.send_message("You must provide a recipient.", ephemeral=True) return - event_channel: nextcord.TextChannel = interaction.guild.get_channel( - self.bot.config.params.event_post_channel_id - ) + event_channel: nextcord.TextChannel = interaction.guild.get_channel(settings.channel_ids.event_post) msg = f"<@{interaction.user.id}> has given {recipient_str} points for the {activity} activity. Justification: {justification}" # noqa: E501 if not msg.endswith("."): @@ -155,11 +151,10 @@ class EventView(nextcord.ui.View): Also contains a UserSelect object to pick discord members. """ - def __init__(self, name: str, config: DakinyConfig, host_id: int): + def __init__(self, name: str, host_id: int): super().__init__() self.name: str = name - self.config: DakinyConfig = config self.host_id: int = host_id self.event_participants = ParticipantSelect() @@ -189,9 +184,8 @@ class EventView(nextcord.ui.View): if discord_users: discord_users_list: list[str] = [str(user.id) for user in discord_users if user.id is not self.host_id] record_event_points( - self.config, discord_users_list, - self.config.params.event_participate_points, + settings.event_settings.participate_points, is_member=True, ) @@ -199,15 +193,14 @@ class EventView(nextcord.ui.View): if non_discord_users: non_discord_users_list: list[str] = non_discord_users.split("\n") record_event_points( - self.config, non_discord_users_list, - self.config.params.event_participate_points, + settings.event_settings.participate_points, is_member=False, ) - record_event_points(self.config, [self.host_id], self.config.params.event_host_points, is_member=True) + record_event_points([self.host_id], settings.event_settings.host_points, is_member=True) - event_channel: nextcord.TextChannel = interaction.guild.get_channel(self.config.params.event_post_channel_id) + event_channel: nextcord.TextChannel = interaction.guild.get_channel(settings.channel_ids.event_post) await event_channel.send(embed=interaction.message.embeds[0]) await interaction.response.edit_message(content="Event has been submitted.", view=None, embed=None) diff --git a/cogs/commands/refresh.py b/cogs/commands/refresh.py index 2831c1d..a42cecc 100644 --- a/cogs/commands/refresh.py +++ b/cogs/commands/refresh.py @@ -61,5 +61,5 @@ class RefreshCog(commands.Cog, name="Refresh Commands"): Args: interaction (nextcord.Interaction): Interaction with the command. """ - await edit_clan_council_info(interaction.guild, self.bot.config) + await edit_clan_council_info(interaction.guild) await interaction.response.send_message("Clan Council Info message updated.", ephemeral=True) diff --git a/cogs/commands/request.py b/cogs/commands/request.py index c80e39d..aa5ebf1 100644 --- a/cogs/commands/request.py +++ b/cogs/commands/request.py @@ -1,16 +1,12 @@ """Contains commands and views for request commands.""" -from typing import TYPE_CHECKING - import nextcord from nextcord.ext import commands from sqlalchemy.orm import Session +from DakinySettings import settings from database_setup.sql_data_classes import Presences, engine -if TYPE_CHECKING: - from config import DakinyConfig - class RequestCog(commands.Cog, name="Request Commands"): """Class holds request commands.""" @@ -41,10 +37,9 @@ class RequestCog(commands.Cog, name="Request Commands"): interaction (nextcord.Interaction): Interaction that invoked the command. presence (str): The presence to add. """ - config: DakinyConfig = self.bot.config content = f'<@{interaction.user.id}> would like to add presence "{presence}."' view = PresenceChange(presence) - await self.bot.get_channel(config.params.admin_channel_id).send(content=content, view=view) + await self.bot.get_channel(settings.channel_ids.admin).send(content=content, view=view) await interaction.response.send_message("Request sent to admins.", ephemeral=True) @request.subcommand(description="Request to change your Dakiny nickname") @@ -65,10 +60,9 @@ class RequestCog(commands.Cog, name="Request Commands"): interaction (nextcord.Interaction): Interaction that invoked the command. new_nickname(str): The username to change to. """ - config: DakinyConfig = self.bot.config content = f'<@{interaction.user.id}> would like to change their username to "{new_nickname}."' view = UsernameRequest(interaction.user.id, new_nickname) - await self.bot.get_channel(config.params.admin_channel_id).send(content=content, view=view) + await self.bot.get_channel(settings.channel_ids.admin).send(content=content, view=view) await interaction.response.send_message("Request sent to admins.", ephemeral=True) diff --git a/cogs/commands/test.py b/cogs/commands/test.py index 9226496..789d1d4 100644 --- a/cogs/commands/test.py +++ b/cogs/commands/test.py @@ -1,17 +1,12 @@ """Commands for testing.""" -from typing import TYPE_CHECKING - import nextcord from nextcord.ext import application_checks, commands from classes.election import Election +from DakinySettings import settings from utils import GUILDS, get_current_election_cycle -if TYPE_CHECKING: - from config import DakinyConfig - - ME = 206602713511886849 @@ -44,11 +39,9 @@ class TestCog(commands.Cog, name="Test commands."): Args: interaction (nextcord.Interaction): Interaction with the message. """ - config: DakinyConfig = self.bot.config cycle = Election( - get_current_election_cycle(config), - config, - self.bot.get_guild(config.params.guild_id), + get_current_election_cycle(), + self.bot.get_guild(settings.params.guild_id), ) await cycle.election_start_action() await interaction.send("Test command sent.", ephemeral=True) @@ -62,11 +55,9 @@ class TestCog(commands.Cog, name="Test commands."): Args: interaction (nextcord.Interaction): Interaction with the message. """ - config: DakinyConfig = self.bot.config cycle = Election( - get_current_election_cycle(config), - config, - self.bot.get_guild(config.params.guild_id), + get_current_election_cycle(), + self.bot.get_guild(settings.params.guild_id), ) await cycle.voting_start_action() await interaction.send("Test command sent.", ephemeral=True) @@ -80,11 +71,9 @@ class TestCog(commands.Cog, name="Test commands."): Args: interaction (nextcord.Interaction): Interaction with the message. """ - config: DakinyConfig = self.bot.config cycle = Election( - get_current_election_cycle(config), - config, - self.bot.get_guild(config.params.guild_id), + get_current_election_cycle(), + self.bot.get_guild(settings.params.guild_id), ) await cycle.voting_end_action() await interaction.send("Test command sent.", ephemeral=True) @@ -98,11 +87,9 @@ class TestCog(commands.Cog, name="Test commands."): Args: interaction (nextcord.Interaction): Interaction with the message. """ - config: DakinyConfig = self.bot.config cycle = Election( - get_current_election_cycle(config), - config, - self.bot.get_guild(config.params.guild_id), + get_current_election_cycle(), + self.bot.get_guild(settings.params.guild_id), ) await cycle.highcouncil_election_start_action() await interaction.send("Test command sent.", ephemeral=True) @@ -116,11 +103,9 @@ class TestCog(commands.Cog, name="Test commands."): Args: interaction (nextcord.Interaction): Interaction with the message. """ - config: DakinyConfig = self.bot.config cycle = Election( - get_current_election_cycle(config), - config, - self.bot.get_guild(config.params.guild_id), + get_current_election_cycle(), + self.bot.get_guild(settings.params.guild_id), ) await cycle.election_reminder() await interaction.send("Test command sent.", ephemeral=True) @@ -134,11 +119,9 @@ class TestCog(commands.Cog, name="Test commands."): Args: interaction (nextcord.Interaction): Interaction with the message. """ - config: DakinyConfig = self.bot.config cycle = Election( - get_current_election_cycle(config), - config, - self.bot.get_guild(config.params.guild_id), + get_current_election_cycle(), + self.bot.get_guild(settings.params.guild_id), ) await cycle.check_date() await interaction.send("Test command sent.", ephemeral=True) @@ -152,11 +135,9 @@ class TestCog(commands.Cog, name="Test commands."): Args: interaction (nextcord.Interaction): Interaction with the message. """ - config: DakinyConfig = self.bot.config cycle = Election( - get_current_election_cycle(config), - config, - self.bot.get_guild(config.params.guild_id), + get_current_election_cycle(), + self.bot.get_guild(settings.params.guild_id), ) await cycle.term_start_action() await interaction.send("Test command sent.", ephemeral=True) diff --git a/cogs/loops/daily_loop.py b/cogs/loops/daily_loop.py index 61b6c45..ac9daf5 100644 --- a/cogs/loops/daily_loop.py +++ b/cogs/loops/daily_loop.py @@ -10,6 +10,7 @@ from sqlalchemy import select from sqlalchemy.orm import Session from classes.election import Election +from DakinySettings import settings from database_setup.sql_data_classes import UserBirthday, engine from main import birthday_list from utils import get_current_election_cycle @@ -17,8 +18,6 @@ from utils import get_current_election_cycle if TYPE_CHECKING: import nextcord - from config import DakinyConfig - KANDY = 239547993106284544 @@ -76,14 +75,13 @@ class DailyLoop(commands.Cog, name="Daily Loop"): Returns: Election: Current election cycle, None if there is no election happening. """ - config: DakinyConfig = self.bot.config - cycle = get_current_election_cycle(config) + cycle = get_current_election_cycle() # prevent exception from using cycle as an Int in an array if cycle is None: return None - return Election(cycle, config, self.bot.get_guild(config.params.guild_id)) + return Election(cycle, self.bot.get_guild(settings.params.guild_id)) def update_birthdays(self) -> None: """Goes through database to collect all birthdays that are today. Adds user's id to birthday list.""" @@ -108,8 +106,8 @@ class DailyLoop(commands.Cog, name="Daily Loop"): Sends a message saying happy cakeday. """ today = datetime.now(tz=UTC).date() - 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) + guild: nextcord.Guild = self.bot.get_guild(settings.params.guild_id) + announce_channel: nextcord.TextChannel = guild.get_channel(settings.channel_ids.general) cakedays: list[nextcord.Member] = [ human for human in guild.humans if human.joined_at.month == today.month and human.joined_at.day == today.day diff --git a/config.py b/config.py deleted file mode 100644 index 3ba32f1..0000000 --- a/config.py +++ /dev/null @@ -1,49 +0,0 @@ -"""File contains classes defining the Hydra configuraton structure.""" - -from dataclasses import dataclass - - -@dataclass -class Params: - """Class defines the various configuration parameters.""" - - admin_channel_id: int # might want to rename this... - announcement_category_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 - event_host_points: int - event_host_role_id: int - event_participate_points: int - event_points_weekly_limit: int - event_post_channel_id: int - general_channel_id: int - git_branch: str - guild_id: int - high_council_role_id: int - voting_parent_id: int - - -@dataclass -class Election: - """Class defines relevant election dates.""" - - election_start: str - highcouncil_election_announce: str - highcouncil_election_end: str - highcouncil_election_start: str - name: str - term_end: str - term_start: str - voting_end: str - voting_start: str - - -@dataclass -class DakinyConfig: - """Class defines all configs required for Dakiny Bot.""" - - election_cycles: list[Election] - params: Params diff --git a/main.py b/main.py index 7aab9bd..ef9bfb8 100644 --- a/main.py +++ b/main.py @@ -2,23 +2,17 @@ import logging import os -import sys -import hydra import nextcord -from hydra.core.config_store import ConfigStore from nextcord.ext import commands from classes.nominate_highcouncil_views import NominateHighCouncilView from classes.nominate_views import NominateView from classes.voting_highcouncil_views import VoteHighcouncilView from classes.voting_views import VoteView -from config import DakinyConfig +from DakinySettings import settings from database_setup import create_database -cs = ConfigStore.instance() -cs.store(name="dakiny_config", node=DakinyConfig) - birthday_list: list[int] = [] logger = logging.getLogger("nextcord") @@ -28,26 +22,19 @@ handler.setFormatter(logging.Formatter("%(asctime)s:%(levelname)s:%(name)s: %(me logger.addHandler(handler) -@hydra.main(config_path="conf", config_name="config") -def main(cfg: DakinyConfig) -> None: - """ - Builds and runs bot. - - Args: - cfg (DakinyConfig): Passed in hydra configuration. - """ - # Allows privledged intents for monitoring members joining, roles editing, and role assignments +def main() -> None: + """Builds and runs bot.""" + # Allows privileged intents for monitoring members joining, roles editing, and role assignments # These need to be enabled in the developer portal as well intents = nextcord.Intents.default() # Required in order to read messages (eg. prefix commands) intents.message_content = True - # To enable the members priveleged intent: + # To enable the members privileged intent: intents.members = True bot = commands.Bot(intents=intents) - bot.config = cfg # Get the modules of all cogs whose directory structure is ./cogs/ for folder in os.listdir("cogs"): @@ -58,18 +45,15 @@ def main(cfg: DakinyConfig) -> None: """When Discord is connected.""" assert bot.user is not None # noqa: S101 documentation does this create_database # noqa: B018 - bot.add_view(NominateView(cfg, bot.get_guild(cfg.params.guild_id))) - bot.add_view(NominateHighCouncilView(cfg, bot.get_guild(cfg.params.guild_id))) - bot.add_view(VoteView(cfg, bot.get_guild(cfg.params.guild_id))) - bot.add_view(VoteHighcouncilView(cfg, bot.get_guild(cfg.params.guild_id))) + bot.add_view(NominateView(bot.get_guild(settings.params.guild_id))) + bot.add_view(NominateHighCouncilView(bot.get_guild(settings.params.guild_id))) + bot.add_view(VoteView(bot.get_guild(settings.params.guild_id))) + bot.add_view(VoteHighcouncilView(bot.get_guild(settings.params.guild_id))) print(f"{bot.user.name} has connected to Discord!") # noqa: T201 TODO make logging to print my stuff to console # Run Discord bot - bot.run(bot.config.params.discord_token) + bot.run(settings.params.discord_token) if __name__ == "__main__": - sys.argv.append("hydra.job.chdir=False") - sys.argv.append("hydra/job_logging=none") - sys.argv.append("hydra/hydra_logging=none") - main() # pylint: disable=no-value-for-parameter + main() diff --git a/pyproject.toml b/pyproject.toml index 53f77b3..4e74b55 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,14 +10,13 @@ package-mode = false python = "^3.12" gitpython = "^3.1.43" fastapi = "^0.111.0" -hydra-core = "^1.3.2" nextcord = "^2.6.0" pandas = "^2.2.2" -python-dotenv = "^1.0.1" pytz = "^2024.1" sqlalchemy = "^2.0.30" aiofiles = "^23.2.1" setuptools = "^70.0.0" +dataclass-wizard = "^0.22.3" [tool.poetry.group.dev.dependencies] diff --git a/utils.py b/utils.py index 091fee2..2531bd0 100644 --- a/utils.py +++ b/utils.py @@ -12,7 +12,7 @@ import nextcord from sqlalchemy import select, true, update from sqlalchemy.orm import Session -from config import DakinyConfig +from DakinySettings import settings from database_setup.sql_data_classes import ( CouncilMembers, EventPoints, @@ -57,50 +57,41 @@ def get_datetime(day: str) -> datetime: return datetime(year, month, day, tzinfo=UTC) -def get_election_name(config: DakinyConfig) -> str: +def get_election_name() -> str: """ Builds the unique name of the current election cycle. - Args: - config (DakinyConfig): the config used to know the election cycle. - Returns: str: the name of the election cycle """ - cycle = get_current_election_cycle(config) - current_cycle = config.election_cycles[cycle] + cycle = get_current_election_cycle() + current_cycle = settings.election_cycles[cycle] return f"vote-{get_datetime(current_cycle.term_start).year}-{current_cycle.name}" -def get_quarter_name(config: DakinyConfig) -> str: +def get_quarter_name() -> str: """ Builds the name of the current cycle/quarter. - Args: - config (DakinyConfig): the config used to know the election cycle. - Returns: str: the name of the cycle. """ - cycle = get_quarter_cycle(config) - current_cycle = config.election_cycles[cycle] + cycle = get_quarter_cycle() + current_cycle = settings.election_cycles[cycle] return f"{get_datetime(current_cycle.term_start).year}-{current_cycle.name}" -def get_current_election_cycle(config: DakinyConfig) -> int: +def get_current_election_cycle() -> int: """ Returns index for active election. An election is considered active between the election start and the term start. - Args: - config (DakinyConfig): Config object to use - Returns: int: cycle index for active election. None for no active cycle """ today = datetime.now(tz=UTC) - for cycle, election in enumerate(config.election_cycles): + for cycle, election in enumerate(settings.election_cycles): if ( today.date() >= get_datetime(election.election_start).date() and today.date() <= get_datetime(election.term_start).date() @@ -108,21 +99,18 @@ def get_current_election_cycle(config: DakinyConfig) -> int: return cycle # It isn't a current election, get the quarter - return get_quarter_cycle(config) + return get_quarter_cycle() -def get_quarter_cycle(config: DakinyConfig) -> int: +def get_quarter_cycle() -> int: """ Returns the index for the current cycle/quarter. Defined as between term start and end. Shouldn't return none. - Args: - config (DakinyConfig): Config object to use - Returns: int: cycle index for current cycle. """ today = datetime.now(tz=UTC) - for cycle, election in enumerate(config.election_cycles): + for cycle, election in enumerate(settings.election_cycles): if ( today.date() >= get_datetime(election.term_start).date() and today.date() <= get_datetime(election.term_end).date() @@ -132,12 +120,11 @@ def get_quarter_cycle(config: DakinyConfig) -> int: return None -def build_votes_str(config: DakinyConfig, guild: nextcord.Guild) -> str: +def build_votes_str(guild: nextcord.Guild) -> str: """ Creates a string that contains all nominees and their votes to be sent as a discord message. Args: - config (DakinyConfig): Dakiny config object guild (nextcord.Guild): The guild object. Used to get display names for sorting. Returns: @@ -145,7 +132,7 @@ def build_votes_str(config: DakinyConfig, guild: nextcord.Guild) -> str: """ votes: dict[int, int] = {} - election_name = get_election_name(config) + election_name = get_election_name() with Session(engine) as session: stmt = select(CouncilMembers).where(CouncilMembers.ElectionName == election_name) @@ -168,12 +155,11 @@ def build_votes_str(config: DakinyConfig, guild: nextcord.Guild) -> str: return votes_str -def build_highcouncil_votes_str(config: DakinyConfig, guild: nextcord.Guild) -> str: +def build_highcouncil_votes_str(guild: nextcord.Guild) -> str: """ Creates a string that contains all high council nominees and their votes to be sent as a discord message. Args: - config (DakinyConfig): Dakiny config object guild (nextcord.Guild): The guild object. Used to get display names for sorting. Returns: @@ -182,7 +168,7 @@ def build_highcouncil_votes_str(config: DakinyConfig, guild: nextcord.Guild) -> cl_votes: dict[int, int] = {} dm_votes: dict[int, int] = {} - election_name = get_election_name(config) + election_name = get_election_name() with Session(engine) as session: stmt = ( @@ -302,7 +288,7 @@ def decorate_dm_nomination(user_id: int, speech: str) -> str: return msg -def record_event_points(config: DakinyConfig, users: Sequence[str], add_points: int, *, is_member: bool) -> None: +def record_event_points(users: Sequence[str], add_points: int, *, is_member: bool) -> None: """ Adds event points to all users listed. @@ -310,19 +296,18 @@ def record_event_points(config: DakinyConfig, users: Sequence[str], add_points: adds points to the existing value. Can be used for hosting or participating. Args: - config (DakinyConfig): Dakiny config for getting points users (Sequence[int]): users that participated and need points. add_points (int): number of points to add is_member (bool): whether the users are a discord member or not """ - quarter_name = get_quarter_name(config) + quarter_name = get_quarter_name() with Session(engine) as session: for user in users: stmt = select(EventPoints).where(EventPoints.UserId == user).where(EventPoints.QuarterName == quarter_name) points = session.scalar(stmt) if points is None: - add_points = get_allowed_points(session, config.params.event_points_weekly_limit, user, add_points) + add_points = get_allowed_points(session, settings.event_settings.weekly_limit, user, add_points) new_points = EventPoints( QuarterName=quarter_name, UserId=user, @@ -331,7 +316,7 @@ def record_event_points(config: DakinyConfig, users: Sequence[str], add_points: ) session.add(new_points) else: - add_points = get_allowed_points(session, config.params.event_points_weekly_limit, user, add_points) + add_points = get_allowed_points(session, settings.event_settings.weekly_limit, user, add_points) points.Points += add_points session.commit() @@ -502,17 +487,16 @@ async def edit_clan_message( session.commit() -async def edit_clan_council_info(guild: nextcord.Guild, config: DakinyConfig) -> None: +async def edit_clan_council_info(guild: nextcord.Guild) -> None: """ Gets the winners of the elections and updates the permanent message that states the current council. Args: guild (nextcord.Guild): Guild object that to use to get channel. - config (DakinyConfig): Configs """ - clan_info_channel: nextcord.TextChannel = await guild.fetch_channel(config.params.clan_info_channel_id) + clan_info_channel: nextcord.TextChannel = await guild.fetch_channel(settings.channel_ids.clan_info) - election_name = get_election_name(config) + election_name = get_election_name() with Session(engine) as session: stmt = ( select(CouncilMembers.MemberId) @@ -540,7 +524,7 @@ async def edit_clan_council_info(guild: nextcord.Guild, config: DakinyConfig) -> f"<@{user_id}>" for user_id in council_member_ids if user_id not in (discord_manager, clan_leader) ] - quarter = get_quarter_name(config) + quarter = get_quarter_name() async with aiofiles.open(f"{TEMPLATES_DIR}/council_members.txt", encoding="utf8") as file: message = await file.read()