From 628152c22c1dd9eff26c0ee6fa05640aaa6f206a Mon Sep 17 00:00:00 2001 From: imcompiling Date: Tue, 3 Sep 2024 13:53:11 -0400 Subject: [PATCH 01/20] Change DakinyConfig.py file name. --- config.py => DakinyConfig.py | 2 +- classes/election.py | 2 +- classes/nominate_highcouncil_views.py | 2 +- classes/nominate_views.py | 2 +- classes/voting_highcouncil_views.py | 2 +- classes/voting_views.py | 2 +- cogs/clan_messages/__init__.py | 2 +- cogs/commands/record.py | 2 +- cogs/commands/request.py | 2 +- cogs/commands/test.py | 2 +- cogs/loops/daily_loop.py | 2 +- utils.py | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) rename config.py => DakinyConfig.py (93%) diff --git a/config.py b/DakinyConfig.py similarity index 93% rename from config.py rename to DakinyConfig.py index 3ba32f1..f67e26c 100644 --- a/config.py +++ b/DakinyConfig.py @@ -1,4 +1,4 @@ -"""File contains classes defining the Hydra configuraton structure.""" +"""File contains classes defining the Hydra configuration structure.""" from dataclasses import dataclass diff --git a/classes/election.py b/classes/election.py index 6ff2011..b21c33f 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 DakinyConfig import DakinyConfig from database_setup.sql_data_classes import ( CouncilMembers, ElectionInformation, diff --git a/classes/nominate_highcouncil_views.py b/classes/nominate_highcouncil_views.py index 620bde9..b007643 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 DakinyConfig import DakinyConfig from database_setup.sql_data_classes import CouncilMembers, engine from nextcord.interactions import Interaction from sqlalchemy import select diff --git a/classes/nominate_views.py b/classes/nominate_views.py index f704420..e637332 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 DakinyConfig import DakinyConfig from database_setup.sql_data_classes import CouncilMembers, engine from nextcord.interactions import Interaction from sqlalchemy import select diff --git a/classes/voting_highcouncil_views.py b/classes/voting_highcouncil_views.py index e3497b2..fb8b7ae 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 DakinyConfig import DakinyConfig from database_setup.sql_data_classes import ( CouncilMembers, ElectionInformation, diff --git a/classes/voting_views.py b/classes/voting_views.py index 4a51238..a6c485c 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 DakinyConfig import DakinyConfig from database_setup.sql_data_classes import ( CouncilMembers, ElectionInformation, diff --git a/cogs/clan_messages/__init__.py b/cogs/clan_messages/__init__.py index 5e3d480..937dece 100644 --- a/cogs/clan_messages/__init__.py +++ b/cogs/clan_messages/__init__.py @@ -14,7 +14,7 @@ from utils import REPO_DIR, edit_clan_council_info, update_clan_messages if TYPE_CHECKING: import nextcord - from config import DakinyConfig + from DakinyConfig import DakinyConfig app = FastAPI() REPO_URL = "https://gitea.cheezers.org/imcompiling/dakiny-messages.git" diff --git a/cogs/commands/record.py b/cogs/commands/record.py index 1aad3b7..d844743 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 DakinyConfig import DakinyConfig from utils import GUILDS, MAX_DISCORD_MESSAGE_LENGTH, record_event_points diff --git a/cogs/commands/request.py b/cogs/commands/request.py index c80e39d..37310d3 100644 --- a/cogs/commands/request.py +++ b/cogs/commands/request.py @@ -9,7 +9,7 @@ from sqlalchemy.orm import Session from database_setup.sql_data_classes import Presences, engine if TYPE_CHECKING: - from config import DakinyConfig + from DakinyConfig import DakinyConfig class RequestCog(commands.Cog, name="Request Commands"): diff --git a/cogs/commands/test.py b/cogs/commands/test.py index 9226496..dfce500 100644 --- a/cogs/commands/test.py +++ b/cogs/commands/test.py @@ -9,7 +9,7 @@ from classes.election import Election from utils import GUILDS, get_current_election_cycle if TYPE_CHECKING: - from config import DakinyConfig + from DakinyConfig import DakinyConfig ME = 206602713511886849 diff --git a/cogs/loops/daily_loop.py b/cogs/loops/daily_loop.py index 61b6c45..a44e72e 100644 --- a/cogs/loops/daily_loop.py +++ b/cogs/loops/daily_loop.py @@ -17,7 +17,7 @@ from utils import get_current_election_cycle if TYPE_CHECKING: import nextcord - from config import DakinyConfig + from DakinyConfig import DakinyConfig KANDY = 239547993106284544 diff --git a/utils.py b/utils.py index 091fee2..455cbfb 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 DakinyConfig import DakinyConfig from database_setup.sql_data_classes import ( CouncilMembers, EventPoints, From b15e99ca68697b20a1cc6926b58ffefe85fd5729 Mon Sep 17 00:00:00 2001 From: imcompiling Date: Tue, 3 Sep 2024 14:14:22 -0400 Subject: [PATCH 02/20] Remove hydra from main. Install PyYAML. --- main.py | 21 +++++---------------- pyproject.toml | 3 +-- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/main.py b/main.py index 7aab9bd..469792d 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 DakinyConfig import DakinyConfig 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,24 @@ 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: +def main() -> None: """ Builds and runs bot. Args: cfg (DakinyConfig): Passed in hydra configuration. """ - # Allows privledged intents for monitoring members joining, roles editing, and role assignments + # 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"): @@ -69,7 +61,4 @@ def main(cfg: DakinyConfig) -> None: 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..3b9aa6d 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" +pyyaml = "^6.0.2" [tool.poetry.group.dev.dependencies] From 62f53bde555e6451e7e47c6afa4000ae19dffbca Mon Sep 17 00:00:00 2001 From: imcompiling Date: Tue, 3 Sep 2024 14:37:06 -0400 Subject: [PATCH 03/20] Renamed to DakinySettings. Converted dataclass to YAMLWizard. --- DakinyConfig.py => DakinySettings.py | 34 ++++++++++++++++++++------- classes/election.py | 6 ++--- classes/nominate_highcouncil_views.py | 14 +++++------ classes/nominate_views.py | 10 ++++---- classes/voting_highcouncil_views.py | 6 ++--- classes/voting_views.py | 6 ++--- cogs/clan_messages/__init__.py | 4 ++-- cogs/commands/record.py | 6 ++--- cogs/commands/request.py | 6 ++--- cogs/commands/test.py | 16 ++++++------- cogs/loops/daily_loop.py | 4 ++-- main.py | 2 +- pyproject.toml | 2 +- utils.py | 18 +++++++------- 14 files changed, 76 insertions(+), 58 deletions(-) rename DakinyConfig.py => DakinySettings.py (65%) diff --git a/DakinyConfig.py b/DakinySettings.py similarity index 65% rename from DakinyConfig.py rename to DakinySettings.py index f67e26c..42465e3 100644 --- a/DakinyConfig.py +++ b/DakinySettings.py @@ -1,11 +1,15 @@ -"""File contains classes defining the Hydra configuration structure.""" +"""File contains classes defining Dakiny settings structure.""" from dataclasses import dataclass +from dataclass_wizard import YAMLWizard + +CONFIG_LOCATION = "conf/config.yaml" + @dataclass -class Params: - """Class defines the various configuration parameters.""" +class Settings: + """Class defines settings editable by Clan Council.""" admin_channel_id: int # might want to rename this... announcement_category_id: int @@ -13,28 +17,34 @@ class Params: 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 Params: + """Class defines start parameters that shouldn't be changed.""" + + discord_token: str + git_branch: str + guild_id: 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 - name: str term_end: str term_start: str voting_end: str @@ -42,8 +52,16 @@ class Election: @dataclass -class DakinyConfig: +class DakinySettings(YAMLWizard): """Class defines all configs required for Dakiny Bot.""" election_cycles: list[Election] params: Params + settings: Settings + + def save(self) -> None: + """Saves settings to the yaml file.""" + self.to_yaml_file(CONFIG_LOCATION) + + +settings = DakinySettings.from_yaml_file(CONFIG_LOCATION) diff --git a/classes/election.py b/classes/election.py index b21c33f..9b50c70 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 DakinyConfig import DakinyConfig +from DakinySettings import DakinySettings from database_setup.sql_data_classes import ( CouncilMembers, ElectionInformation, @@ -39,7 +39,7 @@ class Election: the cycle. """ - def __init__(self, cycle: int, config: DakinyConfig, guild: nextcord.Guild) -> None: + def __init__(self, cycle: int, config: DakinySettings, guild: nextcord.Guild) -> None: """ Generates all dates relevant to the election cycle determined by the config and cycle. @@ -48,7 +48,7 @@ class Election: config (DakinyConfig): The entire config object. guild (nextcord.Guild): The guild that this election is running in. """ - self.config: DakinyConfig = config + self.config: DakinySettings = config self.cycle = cycle self.election_cycle = self.config.election_cycles[self.cycle] self.election_start: datetime = get_datetime(self.election_cycle.election_start) diff --git a/classes/nominate_highcouncil_views.py b/classes/nominate_highcouncil_views.py index b007643..1931a68 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 DakinyConfig import DakinyConfig +from DakinySettings import DakinySettings from database_setup.sql_data_classes import CouncilMembers, engine from nextcord.interactions import Interaction from sqlalchemy import select @@ -23,7 +23,7 @@ class NominateDMModal(nextcord.ui.Modal): def __init__( self, - config: DakinyConfig, + config: DakinySettings, usr_id: int, usr_nominated: bool, # noqa: FBT001 speech_content: str, @@ -33,7 +33,7 @@ class NominateDMModal(nextcord.ui.Modal): timeout=5 * 60, # 5 minutes ) self.usr_id: int = usr_id - self.config: DakinyConfig = config + self.config: DakinySettings = config self.usr_nominated = usr_nominated self.speech = nextcord.ui.TextInput( @@ -85,7 +85,7 @@ class NominateCLModal(nextcord.ui.Modal): def __init__( self, - config: DakinyConfig, + config: DakinySettings, usr_id: int, usr_nominated: bool, # noqa: FBT001 speech_content: str, @@ -95,7 +95,7 @@ class NominateCLModal(nextcord.ui.Modal): timeout=5 * 60, # 5 minutes ) self.usr_id: int = usr_id - self.config: DakinyConfig = config + self.config: DakinySettings = config self.usr_nominated = usr_nominated self.speech = nextcord.ui.TextInput( @@ -141,9 +141,9 @@ 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, config: DakinySettings, guild: nextcord.Guild): super().__init__(timeout=None) - self.config: DakinyConfig = config + self.config: DakinySettings = config self.guild: nextcord.Guild = guild @nextcord.ui.button( diff --git a/classes/nominate_views.py b/classes/nominate_views.py index e637332..e7a6a85 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 DakinyConfig import DakinyConfig +from DakinySettings import DakinySettings from database_setup.sql_data_classes import CouncilMembers, engine from nextcord.interactions import Interaction from sqlalchemy import select @@ -18,7 +18,7 @@ class NominateModal(nextcord.ui.Modal): def __init__( self, - config: DakinyConfig, + config: DakinySettings, usr_id: int, usr_nominated: bool, # noqa: FBT001 speech_content: str, @@ -28,7 +28,7 @@ class NominateModal(nextcord.ui.Modal): timeout=5 * 60, # 5 minutes ) self.usr_id: int = usr_id - self.config: DakinyConfig = config + self.config: DakinySettings = config self.usr_nominated = usr_nominated self.speech = nextcord.ui.TextInput( @@ -79,9 +79,9 @@ 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, config: DakinySettings, guild: nextcord.Guild): super().__init__(timeout=None) - self.config: DakinyConfig = config + self.config: DakinySettings = config self.guild: nextcord.Guild = guild @nextcord.ui.button( diff --git a/classes/voting_highcouncil_views.py b/classes/voting_highcouncil_views.py index fb8b7ae..9096794 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 DakinyConfig import DakinyConfig +from DakinySettings import DakinySettings from database_setup.sql_data_classes import ( CouncilMembers, ElectionInformation, @@ -18,7 +18,7 @@ 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"], config: DakinySettings, election_type: str) -> None: super().__init__( placeholder="Choose 1", min_values=1, @@ -83,7 +83,7 @@ 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, config: DakinySettings, guild: nextcord.Guild): super().__init__(timeout=None) self.config = config self.guild = guild diff --git a/classes/voting_views.py b/classes/voting_views.py index a6c485c..75f54f9 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 DakinyConfig import DakinyConfig +from DakinySettings import DakinySettings from database_setup.sql_data_classes import ( CouncilMembers, ElectionInformation, @@ -18,7 +18,7 @@ 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"], config: DakinySettings) -> None: super().__init__( placeholder="Choose 1", min_values=1, @@ -79,7 +79,7 @@ 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, config: DakinySettings, guild: nextcord.Guild): super().__init__(timeout=None) self.config = config self.guild = guild diff --git a/cogs/clan_messages/__init__.py b/cogs/clan_messages/__init__.py index 937dece..9e6bb22 100644 --- a/cogs/clan_messages/__init__.py +++ b/cogs/clan_messages/__init__.py @@ -14,7 +14,7 @@ from utils import REPO_DIR, edit_clan_council_info, update_clan_messages if TYPE_CHECKING: import nextcord - from DakinyConfig import DakinyConfig + from DakinySettings import DakinySettings app = FastAPI() REPO_URL = "https://gitea.cheezers.org/imcompiling/dakiny-messages.git" @@ -30,7 +30,7 @@ class ClanMessages(commands.Cog, name="Clan Messages"): def __init__(self, bot: commands.Bot): self.bot = bot - self.config: DakinyConfig = self.bot.config + self.config: DakinySettings = self.bot.config self.repo_setup() @commands.Cog.listener() diff --git a/cogs/commands/record.py b/cogs/commands/record.py index d844743..00bcafd 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 DakinyConfig import DakinyConfig +from DakinySettings import DakinySettings from utils import GUILDS, MAX_DISCORD_MESSAGE_LENGTH, record_event_points @@ -155,11 +155,11 @@ 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, config: DakinySettings, host_id: int): super().__init__() self.name: str = name - self.config: DakinyConfig = config + self.config: DakinySettings = config self.host_id: int = host_id self.event_participants = ParticipantSelect() diff --git a/cogs/commands/request.py b/cogs/commands/request.py index 37310d3..4be7acb 100644 --- a/cogs/commands/request.py +++ b/cogs/commands/request.py @@ -9,7 +9,7 @@ from sqlalchemy.orm import Session from database_setup.sql_data_classes import Presences, engine if TYPE_CHECKING: - from DakinyConfig import DakinyConfig + from DakinySettings import DakinySettings class RequestCog(commands.Cog, name="Request Commands"): @@ -41,7 +41,7 @@ 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 + config: DakinySettings = 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) @@ -65,7 +65,7 @@ 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 + config: DakinySettings = 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) diff --git a/cogs/commands/test.py b/cogs/commands/test.py index dfce500..a64de71 100644 --- a/cogs/commands/test.py +++ b/cogs/commands/test.py @@ -9,7 +9,7 @@ from classes.election import Election from utils import GUILDS, get_current_election_cycle if TYPE_CHECKING: - from DakinyConfig import DakinyConfig + from DakinySettings import DakinySettings ME = 206602713511886849 @@ -44,7 +44,7 @@ class TestCog(commands.Cog, name="Test commands."): Args: interaction (nextcord.Interaction): Interaction with the message. """ - config: DakinyConfig = self.bot.config + config: DakinySettings = self.bot.config cycle = Election( get_current_election_cycle(config), config, @@ -62,7 +62,7 @@ class TestCog(commands.Cog, name="Test commands."): Args: interaction (nextcord.Interaction): Interaction with the message. """ - config: DakinyConfig = self.bot.config + config: DakinySettings = self.bot.config cycle = Election( get_current_election_cycle(config), config, @@ -80,7 +80,7 @@ class TestCog(commands.Cog, name="Test commands."): Args: interaction (nextcord.Interaction): Interaction with the message. """ - config: DakinyConfig = self.bot.config + config: DakinySettings = self.bot.config cycle = Election( get_current_election_cycle(config), config, @@ -98,7 +98,7 @@ class TestCog(commands.Cog, name="Test commands."): Args: interaction (nextcord.Interaction): Interaction with the message. """ - config: DakinyConfig = self.bot.config + config: DakinySettings = self.bot.config cycle = Election( get_current_election_cycle(config), config, @@ -116,7 +116,7 @@ class TestCog(commands.Cog, name="Test commands."): Args: interaction (nextcord.Interaction): Interaction with the message. """ - config: DakinyConfig = self.bot.config + config: DakinySettings = self.bot.config cycle = Election( get_current_election_cycle(config), config, @@ -134,7 +134,7 @@ class TestCog(commands.Cog, name="Test commands."): Args: interaction (nextcord.Interaction): Interaction with the message. """ - config: DakinyConfig = self.bot.config + config: DakinySettings = self.bot.config cycle = Election( get_current_election_cycle(config), config, @@ -152,7 +152,7 @@ class TestCog(commands.Cog, name="Test commands."): Args: interaction (nextcord.Interaction): Interaction with the message. """ - config: DakinyConfig = self.bot.config + config: DakinySettings = self.bot.config cycle = Election( get_current_election_cycle(config), config, diff --git a/cogs/loops/daily_loop.py b/cogs/loops/daily_loop.py index a44e72e..91898fb 100644 --- a/cogs/loops/daily_loop.py +++ b/cogs/loops/daily_loop.py @@ -17,7 +17,7 @@ from utils import get_current_election_cycle if TYPE_CHECKING: import nextcord - from DakinyConfig import DakinyConfig + from DakinySettings import DakinySettings KANDY = 239547993106284544 @@ -76,7 +76,7 @@ class DailyLoop(commands.Cog, name="Daily Loop"): Returns: Election: Current election cycle, None if there is no election happening. """ - config: DakinyConfig = self.bot.config + config: DakinySettings = self.bot.config cycle = get_current_election_cycle(config) # prevent exception from using cycle as an Int in an array diff --git a/main.py b/main.py index 469792d..a2ad8c2 100644 --- a/main.py +++ b/main.py @@ -10,7 +10,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 DakinyConfig import DakinyConfig +from DakinySettings import DakinySettings from database_setup import create_database birthday_list: list[int] = [] diff --git a/pyproject.toml b/pyproject.toml index 3b9aa6d..4e74b55 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ pytz = "^2024.1" sqlalchemy = "^2.0.30" aiofiles = "^23.2.1" setuptools = "^70.0.0" -pyyaml = "^6.0.2" +dataclass-wizard = "^0.22.3" [tool.poetry.group.dev.dependencies] diff --git a/utils.py b/utils.py index 455cbfb..f7ab6df 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 DakinyConfig import DakinyConfig +from DakinySettings import DakinySettings from database_setup.sql_data_classes import ( CouncilMembers, EventPoints, @@ -57,7 +57,7 @@ def get_datetime(day: str) -> datetime: return datetime(year, month, day, tzinfo=UTC) -def get_election_name(config: DakinyConfig) -> str: +def get_election_name(config: DakinySettings) -> str: """ Builds the unique name of the current election cycle. @@ -72,7 +72,7 @@ def get_election_name(config: DakinyConfig) -> str: return f"vote-{get_datetime(current_cycle.term_start).year}-{current_cycle.name}" -def get_quarter_name(config: DakinyConfig) -> str: +def get_quarter_name(config: DakinySettings) -> str: """ Builds the name of the current cycle/quarter. @@ -88,7 +88,7 @@ def get_quarter_name(config: DakinyConfig) -> str: 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(config: DakinySettings) -> int: """ Returns index for active election. An election is considered active between the election start and the term start. @@ -111,7 +111,7 @@ def get_current_election_cycle(config: DakinyConfig) -> int: return get_quarter_cycle(config) -def get_quarter_cycle(config: DakinyConfig) -> int: +def get_quarter_cycle(config: DakinySettings) -> int: """ Returns the index for the current cycle/quarter. Defined as between term start and end. Shouldn't return none. @@ -132,7 +132,7 @@ def get_quarter_cycle(config: DakinyConfig) -> int: return None -def build_votes_str(config: DakinyConfig, guild: nextcord.Guild) -> str: +def build_votes_str(config: DakinySettings, guild: nextcord.Guild) -> str: """ Creates a string that contains all nominees and their votes to be sent as a discord message. @@ -168,7 +168,7 @@ 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(config: DakinySettings, guild: nextcord.Guild) -> str: """ Creates a string that contains all high council nominees and their votes to be sent as a discord message. @@ -302,7 +302,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(config: DakinySettings, users: Sequence[str], add_points: int, *, is_member: bool) -> None: """ Adds event points to all users listed. @@ -502,7 +502,7 @@ 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, config: DakinySettings) -> None: """ Gets the winners of the elections and updates the permanent message that states the current council. From 2244765d870542ae6d7490b0a2a404cefd58dfa6 Mon Sep 17 00:00:00 2001 From: imcompiling Date: Tue, 3 Sep 2024 15:05:32 -0400 Subject: [PATCH 04/20] Organized settings better within the dataclass. --- DakinySettings.py | 67 +++++++++++++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 26 deletions(-) diff --git a/DakinySettings.py b/DakinySettings.py index 42465e3..0bdf017 100644 --- a/DakinySettings.py +++ b/DakinySettings.py @@ -8,32 +8,15 @@ CONFIG_LOCATION = "conf/config.yaml" @dataclass -class Settings: - """Class defines settings editable by Clan Council.""" +class ChannelIds: + """Class holds all channel ids needed by bot.""" - 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 - 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 - high_council_role_id: int - voting_parent_id: int - - -@dataclass -class Params: - """Class defines start parameters that shouldn't be changed.""" - - discord_token: str - git_branch: str - guild_id: int + admin: int # might want to rename this... + announcement_category: int + clan_info: int + event_post: int + general: int + voting_parent: int @dataclass @@ -51,13 +34,44 @@ class Election: 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 - settings: Settings + role_ids: RoleIds def save(self) -> None: """Saves settings to the yaml file.""" @@ -65,3 +79,4 @@ class DakinySettings(YAMLWizard): settings = DakinySettings.from_yaml_file(CONFIG_LOCATION) +settings.save() From 3b289e74c8997912517eda70e4c3726b4e36349e Mon Sep 17 00:00:00 2001 From: imcompiling Date: Tue, 3 Sep 2024 15:57:50 -0400 Subject: [PATCH 05/20] Updated files in classes directory to use new configs. Ensured usages are updated. --- classes/election.py | 63 +++++++++++++-------------- classes/nominate_highcouncil_views.py | 33 +++++--------- classes/nominate_views.py | 19 +++----- classes/voting_highcouncil_views.py | 27 +++++------- classes/voting_views.py | 20 ++++----- cogs/commands/test.py | 7 --- cogs/loops/daily_loop.py | 8 ++-- main.py | 10 ++--- 8 files changed, 78 insertions(+), 109 deletions(-) diff --git a/classes/election.py b/classes/election.py index 9b50c70..6dc8145 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 DakinySettings import DakinySettings +from DakinySettings import settings from database_setup.sql_data_classes import ( CouncilMembers, ElectionInformation, @@ -39,7 +39,7 @@ class Election: the cycle. """ - def __init__(self, cycle: int, config: DakinySettings, 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. @@ -48,9 +48,8 @@ class Election: config (DakinyConfig): The entire config object. guild (nextcord.Guild): The guild that this election is running in. """ - self.config: DakinySettings = 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 +73,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 +101,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 +119,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 +132,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 +161,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(settings) thread_msg: nextcord.Message = await parent.send(content=quarter_name) @@ -176,7 +175,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 +200,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(settings)) info = session.scalar(stmt) info.CouncilVoteMsgId = vote_msg.id session.commit() @@ -218,14 +217,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(settings) with Session(engine) as session: # remove vote button from vote message @@ -270,12 +267,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(settings, 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(settings)) info = session.scalar(stmt) info.HighCouncilVoteMsgId = vote_msg.id session.commit() @@ -288,10 +285,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(settings) with Session(engine) as session: # role management @@ -356,7 +353,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(settings) ) vote_msg_id = session.scalar(stmt) vote_msg: nextcord.Message = await election_thread.fetch_message(vote_msg_id) @@ -369,7 +366,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, settings) def get_election_info(self) -> ElectionInformation: """ @@ -379,14 +376,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(settings)) 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 1931a68..cd94b04 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 DakinySettings import DakinySettings +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: DakinySettings, 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: DakinySettings = 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(settings) stmt = ( select(CouncilMembers) .where(CouncilMembers.ElectionName == election_name) @@ -85,7 +83,6 @@ class NominateCLModal(nextcord.ui.Modal): def __init__( self, - config: DakinySettings, 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: DakinySettings = 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(settings) 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: DakinySettings, guild: nextcord.Guild): + def __init__(self, guild: nextcord.Guild): super().__init__(timeout=None) - self.config: DakinySettings = 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(settings) 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(settings) 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 e7a6a85..8f19144 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 DakinySettings import DakinySettings +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: DakinySettings, 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: DakinySettings = 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(settings) 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: DakinySettings, guild: nextcord.Guild): + def __init__(self, guild: nextcord.Guild): super().__init__(timeout=None) - self.config: DakinySettings = 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(settings) 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 9096794..001d21d 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 DakinySettings import DakinySettings +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: DakinySettings, 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(settings) 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(settings, 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: DakinySettings, 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(settings) 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(settings) 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 75f54f9..693fe44 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 DakinySettings import DakinySettings +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: DakinySettings) -> 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(settings) 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: DakinySettings, 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(settings) 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/commands/test.py b/cogs/commands/test.py index a64de71..2de4b7b 100644 --- a/cogs/commands/test.py +++ b/cogs/commands/test.py @@ -47,7 +47,6 @@ class TestCog(commands.Cog, name="Test commands."): config: DakinySettings = self.bot.config cycle = Election( get_current_election_cycle(config), - config, self.bot.get_guild(config.params.guild_id), ) await cycle.election_start_action() @@ -65,7 +64,6 @@ class TestCog(commands.Cog, name="Test commands."): config: DakinySettings = self.bot.config cycle = Election( get_current_election_cycle(config), - config, self.bot.get_guild(config.params.guild_id), ) await cycle.voting_start_action() @@ -83,7 +81,6 @@ class TestCog(commands.Cog, name="Test commands."): config: DakinySettings = self.bot.config cycle = Election( get_current_election_cycle(config), - config, self.bot.get_guild(config.params.guild_id), ) await cycle.voting_end_action() @@ -101,7 +98,6 @@ class TestCog(commands.Cog, name="Test commands."): config: DakinySettings = self.bot.config cycle = Election( get_current_election_cycle(config), - config, self.bot.get_guild(config.params.guild_id), ) await cycle.highcouncil_election_start_action() @@ -119,7 +115,6 @@ class TestCog(commands.Cog, name="Test commands."): config: DakinySettings = self.bot.config cycle = Election( get_current_election_cycle(config), - config, self.bot.get_guild(config.params.guild_id), ) await cycle.election_reminder() @@ -137,7 +132,6 @@ class TestCog(commands.Cog, name="Test commands."): config: DakinySettings = self.bot.config cycle = Election( get_current_election_cycle(config), - config, self.bot.get_guild(config.params.guild_id), ) await cycle.check_date() @@ -155,7 +149,6 @@ class TestCog(commands.Cog, name="Test commands."): config: DakinySettings = self.bot.config cycle = Election( get_current_election_cycle(config), - config, self.bot.get_guild(config.params.guild_id), ) await cycle.term_start_action() diff --git a/cogs/loops/daily_loop.py b/cogs/loops/daily_loop.py index 91898fb..2980e4b 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 DakinySettings import DakinySettings - 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: DakinySettings = self.bot.config - cycle = get_current_election_cycle(config) + cycle = get_current_election_cycle(settings) # 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.""" diff --git a/main.py b/main.py index a2ad8c2..789dd4e 100644 --- a/main.py +++ b/main.py @@ -10,7 +10,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 DakinySettings import DakinySettings +from DakinySettings import settings from database_setup import create_database birthday_list: list[int] = [] @@ -50,10 +50,10 @@ def main() -> 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 From 8dc2668f442e036cae771f0e2f9769bee510b641 Mon Sep 17 00:00:00 2001 From: imcompiling Date: Tue, 3 Sep 2024 16:03:36 -0400 Subject: [PATCH 06/20] Remove config param from get_election_name(). --- classes/election.py | 14 +++++++------- classes/nominate_highcouncil_views.py | 8 ++++---- classes/nominate_views.py | 4 ++-- classes/voting_highcouncil_views.py | 6 +++--- classes/voting_views.py | 4 ++-- utils.py | 17 +++++++---------- 6 files changed, 25 insertions(+), 28 deletions(-) diff --git a/classes/election.py b/classes/election.py index 6dc8145..bc229bb 100644 --- a/classes/election.py +++ b/classes/election.py @@ -162,7 +162,7 @@ class Election: """Performs required actions for when the election cycle starts.""" # create new channel for election parent: nextcord.TextChannel = self.guild.get_channel(settings.channel_ids.voting_parent) - quarter_name: str = get_election_name(settings) + quarter_name: str = get_election_name() thread_msg: nextcord.Message = await parent.send(content=quarter_name) @@ -205,7 +205,7 @@ class Election: ) with Session(engine) as session: - stmt = select(ElectionInformation).where(ElectionInformation.ElectionName == get_election_name(settings)) + stmt = select(ElectionInformation).where(ElectionInformation.ElectionName == get_election_name()) info = session.scalar(stmt) info.CouncilVoteMsgId = vote_msg.id session.commit() @@ -222,7 +222,7 @@ class Election: nominate_msg: nextcord.Message = await election_thread.send(message, view=NominateHighCouncilView(self.guild)) - election_name = get_election_name(settings) + election_name = get_election_name() with Session(engine) as session: # remove vote button from vote message @@ -272,7 +272,7 @@ class Election: ) with Session(engine) as session: - stmt = select(ElectionInformation).where(ElectionInformation.ElectionName == get_election_name(settings)) + stmt = select(ElectionInformation).where(ElectionInformation.ElectionName == get_election_name()) info = session.scalar(stmt) info.HighCouncilVoteMsgId = vote_msg.id session.commit() @@ -288,7 +288,7 @@ class Election: 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(settings) + election_name = get_election_name() with Session(engine) as session: # role management @@ -353,7 +353,7 @@ class Election: # clear view from vote message stmt = select(ElectionInformation.HighCouncilVoteMsgId).where( - ElectionInformation.ElectionName == get_election_name(settings) + ElectionInformation.ElectionName == get_election_name() ) vote_msg_id = session.scalar(stmt) vote_msg: nextcord.Message = await election_thread.fetch_message(vote_msg_id) @@ -376,7 +376,7 @@ 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(settings)) + stmt = select(ElectionInformation).where(ElectionInformation.ElectionName == get_election_name()) return session.scalar(stmt) async def election_reminder(self) -> None: diff --git a/classes/nominate_highcouncil_views.py b/classes/nominate_highcouncil_views.py index cd94b04..e461ac1 100644 --- a/classes/nominate_highcouncil_views.py +++ b/classes/nominate_highcouncil_views.py @@ -56,7 +56,7 @@ class NominateDMModal(nextcord.ui.Modal): with Session(engine) as session: # user already in table - election_name = get_election_name(settings) + election_name = get_election_name() stmt = ( select(CouncilMembers) .where(CouncilMembers.ElectionName == election_name) @@ -116,7 +116,7 @@ class NominateCLModal(nextcord.ui.Modal): with Session(engine) as session: # user already in table - election_name = get_election_name(settings) + election_name = get_election_name() stmt = ( select(CouncilMembers) .where(CouncilMembers.ElectionName == election_name) @@ -165,7 +165,7 @@ class NominateHighCouncilView(nextcord.ui.View): ) return - election_name = get_election_name(settings) + election_name = get_election_name() usr_nominated = False speech_content = "" with Session(engine) as session: @@ -208,7 +208,7 @@ class NominateHighCouncilView(nextcord.ui.View): ) return - election_name = get_election_name(settings) + election_name = get_election_name() usr_nominated = False speech_content = "" with Session(engine) as session: diff --git a/classes/nominate_views.py b/classes/nominate_views.py index 8f19144..3f7858a 100644 --- a/classes/nominate_views.py +++ b/classes/nominate_views.py @@ -48,7 +48,7 @@ class NominateModal(nextcord.ui.Modal): """ speech = decorate_nomination(interaction.user.id, self.speech.value) - election_name = get_election_name(settings) + election_name = get_election_name() with Session(engine) as session: if not self.usr_nominated: @@ -105,7 +105,7 @@ class NominateView(nextcord.ui.View): ) return - election_name = get_election_name(settings) + election_name = get_election_name() usr_nominated = False speech_content = "" with Session(engine) as session: diff --git a/classes/voting_highcouncil_views.py b/classes/voting_highcouncil_views.py index 001d21d..6b595bd 100644 --- a/classes/voting_highcouncil_views.py +++ b/classes/voting_highcouncil_views.py @@ -37,7 +37,7 @@ class VoteSelect(nextcord.ui.StringSelect): Args: interaction (Interaction): Interaction with this callback. """ - election_name: str = get_election_name(settings) + election_name: str = get_election_name() with Session(engine) as session: stmt = select(ElectionInformation.HighCouncilVoteMsgId).where( ElectionInformation.ElectionName == election_name @@ -111,7 +111,7 @@ class VoteHighcouncilView(nextcord.ui.View): ) return - election_name: str = get_election_name(settings) + election_name: str = get_election_name() with Session(engine) as session: stmt = ( @@ -183,7 +183,7 @@ class VoteHighcouncilView(nextcord.ui.View): ) return - election_name: str = get_election_name(settings) + election_name: str = get_election_name() with Session(engine) as session: stmt = ( diff --git a/classes/voting_views.py b/classes/voting_views.py index 693fe44..1ee91fe 100644 --- a/classes/voting_views.py +++ b/classes/voting_views.py @@ -36,7 +36,7 @@ class VoteSelect(nextcord.ui.StringSelect): Args: interaction (Interaction): Interaction with this callback. """ - election_name = get_election_name(settings) + 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) @@ -102,7 +102,7 @@ class VoteView(nextcord.ui.View): ) return - election_name: str = get_election_name(settings) + election_name: str = get_election_name() with Session(engine) as session: stmt = ( diff --git a/utils.py b/utils.py index f7ab6df..9bcba93 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 DakinySettings import DakinySettings +from DakinySettings import settings from database_setup.sql_data_classes import ( CouncilMembers, EventPoints, @@ -57,18 +57,15 @@ def get_datetime(day: str) -> datetime: return datetime(year, month, day, tzinfo=UTC) -def get_election_name(config: DakinySettings) -> 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(settings) + current_cycle = settings.election_cycles[cycle] return f"vote-{get_datetime(current_cycle.term_start).year}-{current_cycle.name}" @@ -145,7 +142,7 @@ def build_votes_str(config: DakinySettings, 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) @@ -182,7 +179,7 @@ def build_highcouncil_votes_str(config: DakinySettings, 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 = ( @@ -512,7 +509,7 @@ async def edit_clan_council_info(guild: nextcord.Guild, config: DakinySettings) """ clan_info_channel: nextcord.TextChannel = await guild.fetch_channel(config.params.clan_info_channel_id) - election_name = get_election_name(config) + election_name = get_election_name() with Session(engine) as session: stmt = ( select(CouncilMembers.MemberId) From 1dd5a33da54f375df5dc4d6abc78819109fda46a Mon Sep 17 00:00:00 2001 From: imcompiling Date: Tue, 3 Sep 2024 16:04:33 -0400 Subject: [PATCH 07/20] Remove config param from get_quarter_name(). --- utils.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/utils.py b/utils.py index 9bcba93..d8495ea 100644 --- a/utils.py +++ b/utils.py @@ -69,7 +69,7 @@ def get_election_name() -> str: return f"vote-{get_datetime(current_cycle.term_start).year}-{current_cycle.name}" -def get_quarter_name(config: DakinySettings) -> str: +def get_quarter_name() -> str: """ Builds the name of the current cycle/quarter. @@ -79,8 +79,8 @@ def get_quarter_name(config: DakinySettings) -> str: Returns: str: the name of the cycle. """ - cycle = get_quarter_cycle(config) - current_cycle = config.election_cycles[cycle] + cycle = get_quarter_cycle(settings) + current_cycle = settings.election_cycles[cycle] return f"{get_datetime(current_cycle.term_start).year}-{current_cycle.name}" @@ -312,7 +312,7 @@ def record_event_points(config: DakinySettings, users: Sequence[str], add_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) @@ -537,7 +537,7 @@ async def edit_clan_council_info(guild: nextcord.Guild, config: DakinySettings) 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() From 62f99022983642906d2510e7be477755cf353cb3 Mon Sep 17 00:00:00 2001 From: imcompiling Date: Tue, 3 Sep 2024 16:07:23 -0400 Subject: [PATCH 08/20] Remove config param from get_current_election_cycle(). Update test.py to use new settings. --- cogs/commands/test.py | 42 ++++++++++++++-------------------------- cogs/loops/daily_loop.py | 2 +- utils.py | 8 ++++---- 3 files changed, 20 insertions(+), 32 deletions(-) diff --git a/cogs/commands/test.py b/cogs/commands/test.py index 2de4b7b..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 DakinySettings import DakinySettings - - ME = 206602713511886849 @@ -44,10 +39,9 @@ class TestCog(commands.Cog, name="Test commands."): Args: interaction (nextcord.Interaction): Interaction with the message. """ - config: DakinySettings = self.bot.config cycle = Election( - get_current_election_cycle(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) @@ -61,10 +55,9 @@ class TestCog(commands.Cog, name="Test commands."): Args: interaction (nextcord.Interaction): Interaction with the message. """ - config: DakinySettings = self.bot.config cycle = Election( - get_current_election_cycle(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) @@ -78,10 +71,9 @@ class TestCog(commands.Cog, name="Test commands."): Args: interaction (nextcord.Interaction): Interaction with the message. """ - config: DakinySettings = self.bot.config cycle = Election( - get_current_election_cycle(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) @@ -95,10 +87,9 @@ class TestCog(commands.Cog, name="Test commands."): Args: interaction (nextcord.Interaction): Interaction with the message. """ - config: DakinySettings = self.bot.config cycle = Election( - get_current_election_cycle(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) @@ -112,10 +103,9 @@ class TestCog(commands.Cog, name="Test commands."): Args: interaction (nextcord.Interaction): Interaction with the message. """ - config: DakinySettings = self.bot.config cycle = Election( - get_current_election_cycle(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) @@ -129,10 +119,9 @@ class TestCog(commands.Cog, name="Test commands."): Args: interaction (nextcord.Interaction): Interaction with the message. """ - config: DakinySettings = self.bot.config cycle = Election( - get_current_election_cycle(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) @@ -146,10 +135,9 @@ class TestCog(commands.Cog, name="Test commands."): Args: interaction (nextcord.Interaction): Interaction with the message. """ - config: DakinySettings = self.bot.config cycle = Election( - get_current_election_cycle(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 2980e4b..c22018e 100644 --- a/cogs/loops/daily_loop.py +++ b/cogs/loops/daily_loop.py @@ -75,7 +75,7 @@ class DailyLoop(commands.Cog, name="Daily Loop"): Returns: Election: Current election cycle, None if there is no election happening. """ - cycle = get_current_election_cycle(settings) + cycle = get_current_election_cycle() # prevent exception from using cycle as an Int in an array if cycle is None: diff --git a/utils.py b/utils.py index d8495ea..2f6ecec 100644 --- a/utils.py +++ b/utils.py @@ -64,7 +64,7 @@ def get_election_name() -> str: Returns: str: the name of the election cycle """ - cycle = get_current_election_cycle(settings) + cycle = get_current_election_cycle() current_cycle = settings.election_cycles[cycle] return f"vote-{get_datetime(current_cycle.term_start).year}-{current_cycle.name}" @@ -85,7 +85,7 @@ def get_quarter_name() -> str: return f"{get_datetime(current_cycle.term_start).year}-{current_cycle.name}" -def get_current_election_cycle(config: DakinySettings) -> 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. @@ -97,7 +97,7 @@ def get_current_election_cycle(config: DakinySettings) -> int: """ 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() @@ -105,7 +105,7 @@ def get_current_election_cycle(config: DakinySettings) -> int: return cycle # It isn't a current election, get the quarter - return get_quarter_cycle(config) + return get_quarter_cycle(settings) def get_quarter_cycle(config: DakinySettings) -> int: From f81e95381e80ba30c3a17ae187535ad7831c9f14 Mon Sep 17 00:00:00 2001 From: imcompiling Date: Tue, 3 Sep 2024 16:08:27 -0400 Subject: [PATCH 09/20] Remove config param from get_quarter_cycle(). --- utils.py | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/utils.py b/utils.py index 2f6ecec..0a5d11d 100644 --- a/utils.py +++ b/utils.py @@ -73,13 +73,10 @@ 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(settings) + cycle = get_quarter_cycle() current_cycle = settings.election_cycles[cycle] return f"{get_datetime(current_cycle.term_start).year}-{current_cycle.name}" @@ -89,9 +86,6 @@ 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 """ @@ -105,21 +99,18 @@ def get_current_election_cycle() -> int: return cycle # It isn't a current election, get the quarter - return get_quarter_cycle(settings) + return get_quarter_cycle() -def get_quarter_cycle(config: DakinySettings) -> 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() From 609fa38f209c2cf85c079f4a001e34cbf8c1e1b1 Mon Sep 17 00:00:00 2001 From: imcompiling Date: Tue, 3 Sep 2024 16:13:35 -0400 Subject: [PATCH 10/20] Remove config param from build_votes_str(). --- utils.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/utils.py b/utils.py index 0a5d11d..a251706 100644 --- a/utils.py +++ b/utils.py @@ -120,12 +120,11 @@ def get_quarter_cycle() -> int: return None -def build_votes_str(config: DakinySettings, 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: From b1f8e9d742dc9739d38c38b1e4c38184bfdca9ed Mon Sep 17 00:00:00 2001 From: imcompiling Date: Tue, 3 Sep 2024 19:27:26 -0400 Subject: [PATCH 11/20] Remove config param from build_highcouncil_votes_str(). --- classes/election.py | 2 +- classes/voting_highcouncil_views.py | 2 +- utils.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/classes/election.py b/classes/election.py index bc229bb..37d95f7 100644 --- a/classes/election.py +++ b/classes/election.py @@ -267,7 +267,7 @@ 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(settings, self.guild), + build_highcouncil_votes_str(self.guild), view=VoteHighcouncilView(self.guild), ) diff --git a/classes/voting_highcouncil_views.py b/classes/voting_highcouncil_views.py index 6b595bd..9ccd3ca 100644 --- a/classes/voting_highcouncil_views.py +++ b/classes/voting_highcouncil_views.py @@ -70,7 +70,7 @@ class VoteSelect(nextcord.ui.StringSelect): session.execute(stmt) session.commit() - vote_message_str = build_highcouncil_votes_str(settings, 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) diff --git a/utils.py b/utils.py index a251706..b176077 100644 --- a/utils.py +++ b/utils.py @@ -155,7 +155,7 @@ def build_votes_str(guild: nextcord.Guild) -> str: return votes_str -def build_highcouncil_votes_str(config: DakinySettings, 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. From 06d81a46042f5fa34d13f524cb85dda1d524f6c4 Mon Sep 17 00:00:00 2001 From: imcompiling Date: Tue, 3 Sep 2024 19:31:40 -0400 Subject: [PATCH 12/20] Remove config param from record_event_points(). --- cogs/commands/record.py | 6 +----- utils.py | 6 +++--- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/cogs/commands/record.py b/cogs/commands/record.py index 00bcafd..982b81a 100644 --- a/cogs/commands/record.py +++ b/cogs/commands/record.py @@ -118,7 +118,6 @@ 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, is_member=True, @@ -126,7 +125,6 @@ class RecordCog(commands.Cog, name="Record Commands"): 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, is_member=False, @@ -189,7 +187,6 @@ 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, is_member=True, @@ -199,13 +196,12 @@ 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, 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], self.config.params.event_host_points, is_member=True) event_channel: nextcord.TextChannel = interaction.guild.get_channel(self.config.params.event_post_channel_id) await event_channel.send(embed=interaction.message.embeds[0]) diff --git a/utils.py b/utils.py index b176077..b2d1608 100644 --- a/utils.py +++ b/utils.py @@ -289,7 +289,7 @@ def decorate_dm_nomination(user_id: int, speech: str) -> str: return msg -def record_event_points(config: DakinySettings, 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. @@ -309,7 +309,7 @@ def record_event_points(config: DakinySettings, users: Sequence[str], add_points 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, @@ -318,7 +318,7 @@ def record_event_points(config: DakinySettings, 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() From 3a47f583829bd97bc8d69140da81c43fa9d8f575 Mon Sep 17 00:00:00 2001 From: imcompiling Date: Tue, 3 Sep 2024 19:33:13 -0400 Subject: [PATCH 13/20] Remove config param from edit_clan_council_info(). --- classes/election.py | 2 +- cogs/clan_messages/__init__.py | 2 +- cogs/commands/refresh.py | 2 +- utils.py | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/classes/election.py b/classes/election.py index 37d95f7..9963650 100644 --- a/classes/election.py +++ b/classes/election.py @@ -366,7 +366,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, settings) + await edit_clan_council_info(self.guild) def get_election_info(self) -> ElectionInformation: """ diff --git a/cogs/clan_messages/__init__.py b/cogs/clan_messages/__init__.py index 9e6bb22..14880e7 100644 --- a/cogs/clan_messages/__init__.py +++ b/cogs/clan_messages/__init__.py @@ -64,7 +64,7 @@ class ClanMessages(commands.Cog, name="Clan Messages"): # 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(self.config.params.guild_id)) return {"message": "Successfully updated all discord messages."} 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/utils.py b/utils.py index b2d1608..d277fd5 100644 --- a/utils.py +++ b/utils.py @@ -489,7 +489,7 @@ async def edit_clan_message( session.commit() -async def edit_clan_council_info(guild: nextcord.Guild, config: DakinySettings) -> 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. @@ -497,7 +497,7 @@ async def edit_clan_council_info(guild: nextcord.Guild, config: DakinySettings) 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() with Session(engine) as session: From 44586183feeafc5b8bc19c68d1db44ccda2800f5 Mon Sep 17 00:00:00 2001 From: imcompiling Date: Tue, 3 Sep 2024 19:43:37 -0400 Subject: [PATCH 14/20] Replace rest of bot.config references. Clear record.py of old config usage. --- cogs/clan_messages/__init__.py | 10 ++++------ cogs/commands/record.py | 31 ++++++++++++++----------------- cogs/commands/request.py | 10 +++------- cogs/loops/daily_loop.py | 4 ++-- main.py | 2 +- 5 files changed, 24 insertions(+), 33 deletions(-) diff --git a/cogs/clan_messages/__init__.py b/cogs/clan_messages/__init__.py index 14880e7..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 DakinySettings import DakinySettings - 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: DakinySettings = 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)) + 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 982b81a..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 DakinySettings import DakinySettings +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 @@ -119,14 +119,14 @@ class RecordCog(commands.Cog, name="Record Commands"): elif recipient is not None: # noqa: RET505 record_event_points( [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( [non_discord_recipient], - self.bot.config.params.event_participate_points, + settings.event_settings.participate_points, is_member=False, ) recipient_str = f'"{non_discord_recipient}"' @@ -134,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("."): @@ -153,11 +151,10 @@ class EventView(nextcord.ui.View): Also contains a UserSelect object to pick discord members. """ - def __init__(self, name: str, config: DakinySettings, host_id: int): + def __init__(self, name: str, host_id: int): super().__init__() self.name: str = name - self.config: DakinySettings = config self.host_id: int = host_id self.event_participants = ParticipantSelect() @@ -188,7 +185,7 @@ class EventView(nextcord.ui.View): discord_users_list: list[str] = [str(user.id) for user in discord_users if user.id is not self.host_id] record_event_points( discord_users_list, - self.config.params.event_participate_points, + settings.event_settings.participate_points, is_member=True, ) @@ -197,13 +194,13 @@ class EventView(nextcord.ui.View): non_discord_users_list: list[str] = non_discord_users.split("\n") record_event_points( non_discord_users_list, - self.config.params.event_participate_points, + settings.event_settings.participate_points, is_member=False, ) - record_event_points([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/request.py b/cogs/commands/request.py index 4be7acb..0d601c8 100644 --- a/cogs/commands/request.py +++ b/cogs/commands/request.py @@ -6,11 +6,9 @@ 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 DakinySettings import DakinySettings - class RequestCog(commands.Cog, name="Request Commands"): """Class holds request commands.""" @@ -41,10 +39,9 @@ class RequestCog(commands.Cog, name="Request Commands"): interaction (nextcord.Interaction): Interaction that invoked the command. presence (str): The presence to add. """ - config: DakinySettings = 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 +62,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: DakinySettings = 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/loops/daily_loop.py b/cogs/loops/daily_loop.py index c22018e..ac9daf5 100644 --- a/cogs/loops/daily_loop.py +++ b/cogs/loops/daily_loop.py @@ -106,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/main.py b/main.py index 789dd4e..80ea8d7 100644 --- a/main.py +++ b/main.py @@ -57,7 +57,7 @@ def main() -> None: 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__": From 4044c8481194ac432b23d7857e5254d96e20d227 Mon Sep 17 00:00:00 2001 From: imcompiling Date: Tue, 3 Sep 2024 19:46:02 -0400 Subject: [PATCH 15/20] Change file copied by Dockerfile. Remove last references to old config in docstrings. --- Dockerfile | 2 +- classes/election.py | 1 - main.py | 7 +------ utils.py | 3 --- 4 files changed, 2 insertions(+), 11 deletions(-) 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 9963650..8a3995b 100644 --- a/classes/election.py +++ b/classes/election.py @@ -45,7 +45,6 @@ class Election: 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.cycle = cycle diff --git a/main.py b/main.py index 80ea8d7..ef9bfb8 100644 --- a/main.py +++ b/main.py @@ -23,12 +23,7 @@ logger.addHandler(handler) def main() -> None: - """ - Builds and runs bot. - - Args: - cfg (DakinyConfig): Passed in hydra configuration. - """ + """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() diff --git a/utils.py b/utils.py index d277fd5..2531bd0 100644 --- a/utils.py +++ b/utils.py @@ -160,7 +160,6 @@ 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: @@ -297,7 +296,6 @@ def record_event_points(users: Sequence[str], add_points: int, *, is_member: boo 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 @@ -495,7 +493,6 @@ async def edit_clan_council_info(guild: nextcord.Guild) -> None: Args: guild (nextcord.Guild): Guild object that to use to get channel. - config (DakinyConfig): Configs """ clan_info_channel: nextcord.TextChannel = await guild.fetch_channel(settings.channel_ids.clan_info) From da7e529502b5d6660b674149544164bcd5410206 Mon Sep 17 00:00:00 2001 From: imcompiling Date: Tue, 3 Sep 2024 19:47:49 -0400 Subject: [PATCH 16/20] Remove unneeded typechecking import. --- cogs/commands/request.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/cogs/commands/request.py b/cogs/commands/request.py index 0d601c8..aa5ebf1 100644 --- a/cogs/commands/request.py +++ b/cogs/commands/request.py @@ -1,7 +1,5 @@ """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 d3084c4ddbe586994c0a55b07b888a033cd53a42 Mon Sep 17 00:00:00 2001 From: imcompiling Date: Thu, 5 Sep 2024 14:49:30 -0400 Subject: [PATCH 17/20] Create new settings command. Create first channel id settings command. --- cogs/commands/__init__.py | 2 ++ cogs/commands/settings.py | 42 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 cogs/commands/settings.py diff --git a/cogs/commands/__init__.py b/cogs/commands/__init__.py index 5c1d3f2..16d5af9 100644 --- a/cogs/commands/__init__.py +++ b/cogs/commands/__init__.py @@ -7,6 +7,7 @@ from cogs.commands.refresh import RefreshCog from cogs.commands.remove import RemoveCog from cogs.commands.request import RequestCog from cogs.commands.set import SetCog +from cogs.commands.settings import SettingsCog from cogs.commands.test import TestCog from cogs.commands.time import TimeCog from cogs.commands.view import ViewCog @@ -21,6 +22,7 @@ def setup(bot: commands.Bot) -> None: bot.add_cog(RemoveCog()) bot.add_cog(RequestCog(bot)) bot.add_cog(SetCog()) + bot.add_cog(SettingsCog()) bot.add_cog(TestCog(bot)) bot.add_cog(TimeCog()) bot.add_cog(ViewCog()) diff --git a/cogs/commands/settings.py b/cogs/commands/settings.py new file mode 100644 index 0000000..389146e --- /dev/null +++ b/cogs/commands/settings.py @@ -0,0 +1,42 @@ +"""Contains commands and views for settings commands.""" + +import nextcord +from nextcord.ext import commands + +from DakinySettings import settings +from utils import GUILDS + + +class SettingsCog(commands.Cog, name="Settings Commands"): + """Class holds settings commands.""" + + def __init__(self) -> None: + """Default constructor for SettingsCog class. Does nothing.""" + + @nextcord.slash_command(guild_ids=GUILDS, default_member_permissions=nextcord.Permissions(administrator=True)) + async def settings(self, interaction: nextcord.Interaction) -> None: + """Parent slash command for settings. Never called.""" + + @settings.subcommand() + async def channel_ids(self, interaction: nextcord.Interaction) -> None: + """Subcommand parent. Never called.""" + + @channel_ids.subcommand(description="Sets channel that bot sends verification requests to admins.") + async def admin( + self, + interaction: nextcord.Interaction, + channel: nextcord.TextChannel = nextcord.SlashOption( + required=False, description="Channel to set to. If left blank, uses current channel." + ), + ) -> None: + """ + Sets DakinySettings channel_ids.admin value to channel id or current channel id. + + Args: + interaction (nextcord.Interaction): Discord interaction of command. + channel (nextcord.TextChannel, optional): Channel to set in settings. + """ + channel_id = interaction.channel_id if channel is None else channel.id + settings.channel_ids.admin = channel_id + settings.save() + await interaction.response.send_message(f"Admin verification channel set to <#{channel_id}>.", ephemeral=True) From be824de52e88736cdef5a6a8f2755b96f44fabc1 Mon Sep 17 00:00:00 2001 From: imcompiling Date: Thu, 5 Sep 2024 15:02:40 -0400 Subject: [PATCH 18/20] Add rest of setting channel id commands. --- DakinySettings.py | 4 +- classes/election.py | 2 +- cogs/commands/settings.py | 104 +++++++++++++++++++++++++++++++++++++- 3 files changed, 106 insertions(+), 4 deletions(-) diff --git a/DakinySettings.py b/DakinySettings.py index 0bdf017..32b9367 100644 --- a/DakinySettings.py +++ b/DakinySettings.py @@ -12,11 +12,11 @@ class ChannelIds: """Class holds all channel ids needed by bot.""" admin: int # might want to rename this... - announcement_category: int + announcement: int clan_info: int event_post: int general: int - voting_parent: int + voting: int @dataclass diff --git a/classes/election.py b/classes/election.py index 8a3995b..f62f89a 100644 --- a/classes/election.py +++ b/classes/election.py @@ -160,7 +160,7 @@ 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(settings.channel_ids.voting_parent) + parent: nextcord.TextChannel = self.guild.get_channel(settings.channel_ids.voting) quarter_name: str = get_election_name() thread_msg: nextcord.Message = await parent.send(content=quarter_name) diff --git a/cogs/commands/settings.py b/cogs/commands/settings.py index 389146e..f67dbce 100644 --- a/cogs/commands/settings.py +++ b/cogs/commands/settings.py @@ -30,7 +30,7 @@ class SettingsCog(commands.Cog, name="Settings Commands"): ), ) -> None: """ - Sets DakinySettings channel_ids.admin value to channel id or current channel id. + Sets DakinySettings channel_ids.admin value to given channel id or current channel id. Args: interaction (nextcord.Interaction): Discord interaction of command. @@ -40,3 +40,105 @@ class SettingsCog(commands.Cog, name="Settings Commands"): settings.channel_ids.admin = channel_id settings.save() await interaction.response.send_message(f"Admin verification channel set to <#{channel_id}>.", ephemeral=True) + + @channel_ids.subcommand(description="Sets announcement channel.") + async def announcement( + self, + interaction: nextcord.Interaction, + channel: nextcord.TextChannel = nextcord.SlashOption( + required=False, description="Channel to set to. If left blank, uses current channel." + ), + ) -> None: + """ + Sets DakinySettings channel_ids.announcement value to given channel id or current channel id. + + Args: + interaction (nextcord.Interaction): Discord interaction of command. + channel (nextcord.TextChannel, optional): Channel to set in settings. + """ + channel_id = interaction.channel_id if channel is None else channel.id + settings.channel_ids.announcement = channel_id + settings.save() + await interaction.response.send_message(f"Announcement channel set to <#{channel_id}>.", ephemeral=True) + + @channel_ids.subcommand(description="Sets clan info channel. Channel used for tracking current council.") + async def clan_info( + self, + interaction: nextcord.Interaction, + channel: nextcord.TextChannel = nextcord.SlashOption( + required=False, description="Channel to set to. If left blank, uses current channel." + ), + ) -> None: + """ + Sets DakinySettings channel_ids.clan_info value to given channel id or current channel id. + + Args: + interaction (nextcord.Interaction): Discord interaction of command. + channel (nextcord.TextChannel, optional): Channel to set in settings. + """ + channel_id = interaction.channel_id if channel is None else channel.id + settings.channel_ids.clan_info = channel_id + settings.save() + await interaction.response.send_message(f"Clan information channel set to <#{channel_id}>.", ephemeral=True) + + @channel_ids.subcommand( + description="Sets event post channel. Channel is where event tracking information is posted." + ) + async def event_post( + self, + interaction: nextcord.Interaction, + channel: nextcord.TextChannel = nextcord.SlashOption( + required=False, description="Channel to set to. If left blank, uses current channel." + ), + ) -> None: + """ + Sets DakinySettings channel_ids.event_post value to given channel id or current channel id. + + Args: + interaction (nextcord.Interaction): Discord interaction of command. + channel (nextcord.TextChannel, optional): Channel to set in settings. + """ + channel_id = interaction.channel_id if channel is None else channel.id + settings.channel_ids.event_post = channel_id + settings.save() + await interaction.response.send_message(f"Event posting channel set to <#{channel_id}>.", ephemeral=True) + + @channel_ids.subcommand(description="Sets general channel.") + async def general( + self, + interaction: nextcord.Interaction, + channel: nextcord.TextChannel = nextcord.SlashOption( + required=False, description="Channel to set to. If left blank, uses current channel." + ), + ) -> None: + """ + Sets DakinySettings channel_ids.general value to given channel id or current channel id. + + Args: + interaction (nextcord.Interaction): Discord interaction of command. + channel (nextcord.TextChannel, optional): Channel to set in settings. + """ + channel_id = interaction.channel_id if channel is None else channel.id + settings.channel_ids.general = channel_id + settings.save() + await interaction.response.send_message(f"General channel set to <#{channel_id}>.", ephemeral=True) + + @channel_ids.subcommand(description="Sets voting channel. Channel used as parent for voting threads.") + async def voting( + self, + interaction: nextcord.Interaction, + channel: nextcord.TextChannel = nextcord.SlashOption( + required=False, description="Channel to set to. If left blank, uses current channel." + ), + ) -> None: + """ + Sets DakinySettings channel_ids.voting value to given channel id or current channel id. + + Args: + interaction (nextcord.Interaction): Discord interaction of command. + channel (nextcord.TextChannel, optional): Channel to set in settings. + """ + channel_id = interaction.channel_id if channel is None else channel.id + settings.channel_ids.voting = channel_id + settings.save() + await interaction.response.send_message(f"Voting channel set to <#{channel_id}>.", ephemeral=True) From 2ba56ead823549cfda3e161f63b41a5c15a283a1 Mon Sep 17 00:00:00 2001 From: imcompiling Date: Thu, 5 Sep 2024 15:21:23 -0400 Subject: [PATCH 19/20] Alphabetically sorted DakinySettings. --- DakinySettings.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/DakinySettings.py b/DakinySettings.py index 32b9367..3af8992 100644 --- a/DakinySettings.py +++ b/DakinySettings.py @@ -23,17 +23,26 @@ class ChannelIds: class Election: """Class defines relevant election dates.""" - name: str 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 EventSettings: + """Class defines settings editable by Clan Council.""" + + host_points: int + participate_points: int + weekly_limit: int + + @dataclass class Params: """Class defines start parameters that shouldn't be changed.""" @@ -47,22 +56,13 @@ class Params: class RoleIds: """Class holds all role ids needed by bot.""" - clan_council_elect: int clan_council: int + clan_council_elect: 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.""" From b42f04aada845a9d546e27cc198f2b0773e8896e Mon Sep 17 00:00:00 2001 From: imcompiling Date: Thu, 5 Sep 2024 15:30:08 -0400 Subject: [PATCH 20/20] Implemented rest of config settings commands. --- cogs/commands/settings.py | 157 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) diff --git a/cogs/commands/settings.py b/cogs/commands/settings.py index f67dbce..3880bb5 100644 --- a/cogs/commands/settings.py +++ b/cogs/commands/settings.py @@ -142,3 +142,160 @@ class SettingsCog(commands.Cog, name="Settings Commands"): settings.channel_ids.voting = channel_id settings.save() await interaction.response.send_message(f"Voting channel set to <#{channel_id}>.", ephemeral=True) + + @settings.subcommand() + async def event_settings(self, interaction: nextcord.Interaction) -> None: + """Subcommand parent. Never called.""" + + @event_settings.subcommand(description="Sets Event Host Points value.") + async def host_points( + self, + interaction: nextcord.Interaction, + points: int = nextcord.SlashOption( + required=True, description="Number of Event Points a host earns when hosting event.", min_value=0 + ), + ) -> None: + """ + Sets DakinySettings event_settings.host_points to the given number of points. + + Args: + interaction (nextcord.Interaction): Discord interaction of command. + points (nextcord.TextChannel): Number of points to set. + """ + settings.event_settings.host_points = points + settings.save() + await interaction.response.send_message(f"Event Host Points set to {points}.", ephemeral=True) + + @event_settings.subcommand(description="Sets Event Participation Points value.") + async def participate_points( + self, + interaction: nextcord.Interaction, + points: int = nextcord.SlashOption( + required=True, + description="Number of Event Points a participant earns when attending an event.", + min_value=0, + ), + ) -> None: + """ + Sets DakinySettings event_settings.participate_points to the given number of points. + + Args: + interaction (nextcord.Interaction): Discord interaction of command. + points (nextcord.TextChannel): Number of points to set. + """ + settings.event_settings.participate_points = points + settings.save() + await interaction.response.send_message(f"Event Participation Points set to {points}.", ephemeral=True) + + @event_settings.subcommand(description="Sets Event Weekly Limit value.") + async def weekly_limit( + self, + interaction: nextcord.Interaction, + points: int = nextcord.SlashOption( + required=True, description="Number of Event Points a clan member can earn in a week.", min_value=0 + ), + ) -> None: + """ + Sets DakinySettings event_settings.weekly_limit to the given number of points. + + Args: + interaction (nextcord.Interaction): Discord interaction of command. + points (nextcord.TextChannel): Number of points to set. + """ + settings.event_settings.weekly_limit = points + settings.save() + await interaction.response.send_message(f"Event Weekly Limit set to {points}.", ephemeral=True) + + @settings.subcommand() + async def role_ids(self, interaction: nextcord.Interaction) -> None: + """Subcommand parent. Never called.""" + + @role_ids.subcommand(description="Sets Clan Council role id.") + async def clan_council( + self, + interaction: nextcord.Interaction, + role: nextcord.Role = nextcord.SlashOption(required=True, description="Role to set."), + ) -> None: + """ + Sets DakinySettings role_ids.clan_council to the given role id. + + Args: + interaction (nextcord.Interaction): Discord interaction of command. + role (nextcord.TextChannel): Role to set in settings. + """ + role_id = role.id + settings.role_ids.clan_council = role_id + settings.save() + await interaction.response.send_message(f"Clan Council role set to <@&{role_id}>.", ephemeral=True) + + @role_ids.subcommand(description="Sets Clan Council Elect role id.") + async def clan_council_elect( + self, + interaction: nextcord.Interaction, + role: nextcord.Role = nextcord.SlashOption(required=True, description="Role to set."), + ) -> None: + """ + Sets DakinySettings role_ids.clan_council_elect to the given role id. + + Args: + interaction (nextcord.Interaction): Discord interaction of command. + role (nextcord.TextChannel): Role to set in settings. + """ + role_id = role.id + settings.role_ids.clan_council_elect = role_id + settings.save() + await interaction.response.send_message(f"Clan Council Elect role set to <@&{role_id}>.", ephemeral=True) + + @role_ids.subcommand(description="Sets Clan Member role id.") + async def clan_member( + self, + interaction: nextcord.Interaction, + role: nextcord.Role = nextcord.SlashOption(required=True, description="Role to set."), + ) -> None: + """ + Sets DakinySettings role_ids.clan_member to the given role id. + + Args: + interaction (nextcord.Interaction): Discord interaction of command. + role (nextcord.TextChannel): Role to set in settings. + """ + role_id = role.id + settings.role_ids.clan_member = role_id + settings.save() + await interaction.response.send_message(f"Clan Member role set to <@&{role_id}>.", ephemeral=True) + + @role_ids.subcommand(description="Sets Event Host role id.") + async def event_host( + self, + interaction: nextcord.Interaction, + role: nextcord.Role = nextcord.SlashOption(required=True, description="Role to set."), + ) -> None: + """ + Sets DakinySettings role_ids.event_host to the given role id. + + Args: + interaction (nextcord.Interaction): Discord interaction of command. + role (nextcord.TextChannel): Role to set in settings. + """ + role_id = role.id + settings.role_ids.event_host = role_id + settings.save() + await interaction.response.send_message(f"Event Host role set to <@&{role_id}>.", ephemeral=True) + + @role_ids.subcommand(description="Sets High Council role id.") + async def high_council( + self, + interaction: nextcord.Interaction, + role: nextcord.Role = nextcord.SlashOption(required=True, description="Role to set."), + ) -> None: + """ + Sets DakinySettings role_ids.high_council to the given role id. + + Args: + interaction (nextcord.Interaction): Discord interaction of command. + role (nextcord.TextChannel): Role to set in settings. + """ + role_id = role.id + settings.role_ids.high_council = role_id + settings.save() + await interaction.response.send_message(f"High Council role set to <@&{role_id}>.", ephemeral=True)