""" Contains various views to be used in the clan leader nomination process. """ import nextcord from nextcord.interactions import Interaction from sqlalchemy import select from sqlalchemy.orm import Session from config import DakinyConfig from database_setup.sql_data_classes import CouncilMembers, engine from utils import NOMINEE_SPLITTER, decorate_nomination, get_election_cycle_name class NominateCLModal(nextcord.ui.Modal): """ Modal for nominating oneself. User writes a speech and then the callback sends the speech into the correct channel. """ def __init__( self, config: DakinyConfig, usr_id: int, usr_nominated: bool, speech_content: str, ): super().__init__( "Clan Leader Nomination", timeout=5 * 60, # 5 minutes ) self.usr_id: int = usr_id self.config: DakinyConfig = config self.usr_nominated = usr_nominated self.speech = nextcord.ui.TextInput( label="Nomination Speech", style=nextcord.TextInputStyle.paragraph, placeholder="Please write your speech here.", required=True, max_length=1500, default_value=speech_content, ) self.add_item(self.speech) async def callback(self, interaction: Interaction) -> None: """ Sends the nomination speech into the voting channel and enters the user into the voting database. Args: interaction (Interaction): Interaction with user. """ speech = decorate_nomination(interaction.user.id, self.speech.value) with Session(engine) as session: # user already in table cycle = get_election_cycle_name(self.config) stmt = ( select(CouncilMembers) .where(CouncilMembers.ElectionCycle == cycle) .where(CouncilMembers.MemberId == self.usr_id) ) council_elect = session.scalar(stmt) if not self.usr_nominated: msg = await interaction.channel.send(speech) council_elect.ClanLeaderSpeechId = msg.id session.commit() else: msg: nextcord.Message = await interaction.channel.fetch_message( council_elect.ClanLeaderSpeechId ) await msg.edit( content=decorate_nomination(interaction.user.id, self.speech.value) ) class NominateCLView(nextcord.ui.View): """ The button to press to start your Clan Leader nomination. """ def __init__(self, config: DakinyConfig, guild: nextcord.Guild): super().__init__(timeout=None) self.config: DakinyConfig = config self.guild: nextcord.Guild = guild @nextcord.ui.button( label="Nominate for Clan Leader", style=nextcord.ButtonStyle.primary, custom_id="nominate-cl", ) async def nominate( self, button: nextcord.ui.Button, interaction: nextcord.Interaction ) -> None: """ Gathers previous information about the user if they have already nominated themselves, then launches the nomination modal to get their speech. Args: button (nextcord.ui.Button): Unused. idk why its needed in the decorator 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 ): await interaction.response.send_message( f"You must have the <@&{self.config.params.clan_council_elect_role_id}> role to vote.", ephemeral=True, ) return cycle = get_election_cycle_name(self.config) usr_nominated = False speech_content = "" with Session(engine) as session: stmt = ( select(CouncilMembers) .where(CouncilMembers.ElectionCycle == cycle) .where(CouncilMembers.MemberId == interaction.user.id) ) obj = session.scalar(stmt) # user needs to exist to get here anyways... if obj.ClanLeaderSpeechId is not None: usr_nominated = True 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 ) )