import discord import os # default module from dotenv import load_dotenv import json import mariadb import sys from discord import default_permissions configfile = "config.json" if os.path.exists(configfile): with open('config.json') as user_file: config = json.loads(user_file.read()) else: config = {"db_user": os.environ["db_user"], "db_password": os.environ["db_password"], "db_host": os.environ["db_host"], "db_name": os.environ["db_name"]} if os.path.exists(".env"): load_dotenv() def connect_db(): try: conn = mariadb.connect( user=config["db_user"], password=config["db_password"], host=config["db_host"], port=3306, database=config["db_name"] ) return conn except mariadb.Error as e: print(f"Error connecting to MariaDB Platform: {e}") sys.exit(1) def recruit_update(member, recruit, cur, conn): cur.execute("INSERT INTO recruits (discord_id, nickname, recruit) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE nickname=?, recruit=?;", (member.id, member.display_name, recruit, member.display_name, recruit)) conn.commit() intents = discord.Intents.default() intents.members = True bot = discord.Bot(intents = intents) @bot.event async def on_ready(): global Yes_select_inst25 Yes_select_inst25 = Yes_select_25() bot.add_view(Yes_select_inst25) global Yes_select_inst50 Yes_select_inst50 = Yes_select_50() bot.add_view(Yes_select_inst50) global no_select_inst25 no_select_inst25 = No_select25() bot.add_view(no_select_inst25) global no_select_inst50 no_select_inst50 = No_select50() bot.add_view(no_select_inst50) bot.add_view(delete_and_view_votes_message()) bot.add_view(report_buttons()) print(f"{bot.user} is ready and online!") conn = connect_db() cur = conn.cursor() # create Slash Command group with bot.create_group settings = bot.create_group("set", "Einstellungen") def get_count_recruits(real = 0): cur.execute("SELECT count(*) FROM recruits WHERE recruit=1") count = cur.fetchone()[0] if real == 0: if count > 25: count = count / 2 return int(count) def build_option_list(part=1): cur.execute("SELECT discord_id, nickname, recruit FROM recruits WHERE recruit=1") options = [] records = cur.fetchall() count = get_count_recruits(1) counter = 0 if count <= 25: for row in records: options.append(discord.SelectOption(value=str(row[0]), label=str(row[1]))) counter = counter + 1 return options, counter else: i = 0 for row in records: if part == 1: if i > (count / 2): break elif part == 2: if i <= (count / 2): i = i + 1 continue options.append(discord.SelectOption(value=str(row[0]), label=str(row[1]))) i = i + 1 counter = counter + 1 return options, counter def insert_yes_vote(recruit_id, voter_id): cur.execute("SELECT discord_id_recruit, discord_id_voter FROM yes_votes WHERE discord_id_recruit = ? AND discord_id_voter = ?", (recruit_id, voter_id)) result = cur.fetchone() if result is None: cur.execute("INSERT INTO yes_votes(discord_id_recruit, discord_id_voter) VALUES (?, ?)", (recruit_id, voter_id)) conn.commit() cur.execute("SELECT nickname FROM recruits WHERE discord_id = ?", (recruit_id, )) return cur.fetchone()[0] async def send_yes_confirm(select, interaction): message = "Du hast für folgende Rekruten mit **Ja** abgestimmt:\n\n" for recruit in select.values: member = insert_yes_vote(recruit, interaction.user.id) message = message + member + "\n" embed = discord.Embed( title="Aktion abgeschlossen", description=message, color=discord.Colour.green(), ) await edit_report_message() await interaction.response.send_message(embed=embed, ephemeral=True) class yes_question_cause_overlap(discord.ui.View): vote_ids = [] @discord.ui.button(label="Nein-Stimmen löschen und mit Ja stimmen", style=discord.ButtonStyle.primary) async def yes(self, button, interaction): for vote_id in self.vote_ids: cur.execute("DELETE FROM no_votes WHERE id = ?", (vote_id, )) conn.commit() await self.message.delete() await send_yes_confirm(self.select, interaction) @discord.ui.button(label="Abbrechen", style=discord.ButtonStyle.secondary) async def no(self, button, interaction): embed = discord.Embed( title="Aktion abgebrochen", description="HALT STOPP", color=discord.Colour.green(), ) await self.message.delete() await interaction.response.send_message(embed=embed, ephemeral=True) async def on_timeout(self): self.clear_items() async def process_yes_vote(select, interaction): found = False overlap_embed = discord.Embed( title="Stimmen bereits vorhanden", description="Für folgende Rekruten hast du bereits mit Nein gestimmt. Möchtest du diese Stimmen löschen und mit Ja stimmen?", color=discord.Colour.green(), ) yes_question_cause_overlap_inst = yes_question_cause_overlap() for yes_vote in select.values: cur.execute( "SELECT recruits.nickname, no_votes.reason, no_votes.id FROM recruits, no_votes WHERE no_votes.discord_id_recruit = recruits.discord_id AND no_votes.discord_id_voter = ? AND no_votes.discord_id_recruit = ?", (interaction.user.id, yes_vote)) result = cur.fetchall() if result: found = True overlap_embed.add_field(name=result[0][0], value=result[0][1]) yes_question_cause_overlap_inst.vote_ids.append(result[0][2]) if found: yes_question_cause_overlap_inst.select = select await interaction.response.send_message(embed=overlap_embed, view=yes_question_cause_overlap_inst, ephemeral=True) else: await send_yes_confirm(select, interaction) class Yes_select_25(discord.ui.View): def __init__(self): super().__init__(timeout=None) # timeout of the view must be set to None @discord.ui.select( custom_id="yes25", placeholder="Rekruten wählen...", min_values=1, max_values=get_count_recruits(), options=build_option_list()[0] ) async def select_callback(self, select, interaction): # the function called when the user is done selecting options await process_yes_vote(select, interaction) class Yes_select_50(discord.ui.View): def __init__(self): super().__init__(timeout=None) # timeout of the view must be set to None @discord.ui.select( custom_id="yes50_1", placeholder="Rekruten wählen...", min_values=1, max_values=build_option_list(1)[1], options=build_option_list(1)[0], row=1 ) async def yes_1_callback(self, select, interaction): # the function called when the user is done selecting options await process_yes_vote(select, interaction) @discord.ui.select( custom_id="yes50_2", placeholder="Rekruten wählen...", min_values=1, max_values=build_option_list(2)[1], options=build_option_list(2)[0], row=2 ) async def yes_2_callback(self, select, interaction): # the function called when the user is done selecting options await process_yes_vote(select, interaction) def create_yes_embed(): embed = discord.Embed( title="Rekrutenbesichtigung: Ja-Stimme", description="Geb hier deine Ja-Stimme für einen Rekruten ab!", color=discord.Colour.green(), ) return embed async def send_yes_message(channel): if get_count_recruits(1) <= 25: message = await channel.send(embed=create_yes_embed(), view=Yes_select_inst25) else: message = await channel.send(embed=create_yes_embed(), view=Yes_select_inst50) cur.execute("UPDATE settings SET VALUE = ? WHERE name = 'message_voting_yes'", (message.id, )) async def edit_yes_message(): cur.execute("SELECT value FROM settings WHERE name='channel_voting'") channel = bot.get_channel(int(cur.fetchone()[0])) cur.execute("SELECT value FROM settings WHERE name='message_voting_yes'") message = await channel.fetch_message(int(cur.fetchone()[0])) conn.commit() if get_count_recruits(1) <= 25: global Yes_select_inst25 optiontuple = build_option_list() Yes_select_inst25.children[0].options = optiontuple[0] Yes_select_inst25.children[0].max_values = optiontuple[1] await message.edit(embed=create_yes_embed(), view=Yes_select_inst25) else: global Yes_select_inst50 optiontuple1 = build_option_list() optiontuple2 = build_option_list(2) Yes_select_inst50.children[0].options = optiontuple1[0] Yes_select_inst50.children[1].options = optiontuple2[0] Yes_select_inst50.children[0].max_values = optiontuple1[1] Yes_select_inst50.children[1].max_values = optiontuple2[1] await message.edit(embed=create_yes_embed(), view=Yes_select_inst50) def insert_no_vote(recruit_id, voter_id, reason): cur.execute("INSERT INTO no_votes(discord_id_recruit, discord_id_voter, reason) VALUES (?, ?, ?)", (recruit_id, voter_id, reason)) conn.commit() cur.execute("SELECT nickname FROM recruits WHERE discord_id = ?", (recruit_id, )) return cur.fetchone()[0] class No_reason(discord.ui.Modal): recruit_name = "" recruit_id = "" def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) self.add_item(discord.ui.InputText(label="Begründung", style=discord.InputTextStyle.long)) async def callback(self, interaction: discord.Interaction): insert_no_vote(self.recruit_id, interaction.user.id, self.children[0].value) await edit_report_message() message = ("Du hast deine Nein-Stimme erfolgreich abgegeben.\n **Hinweis:** Die Rekrutierungsleiter werden sich demnächst bei dir melden.") embed = discord.Embed( title="Aktion abgeschlossen", description=message, color=discord.Colour.green(), ) embed.add_field(name="Rekrut:", value=self.recruit_name) embed.add_field(name="Dein Grund", value=self.children[0].value) await interaction.response.send_message(embeds=[embed], ephemeral=True) async def reason(discord_id, interaction): cur.execute("SELECT nickname FROM recruits WHERE discord_id = ?", (discord_id,)) nickname = cur.fetchone()[0] no_reason_instance = No_reason(title="Begründung für " + nickname) no_reason_instance.recruit_id = discord_id no_reason_instance.recruit_name = nickname await interaction.response.send_modal(no_reason_instance) class no_question(discord.ui.View): discord_id = "" vote_id = "" @discord.ui.button(label="Ja", style=discord.ButtonStyle.green,) async def yes(self, button, interaction): cur.execute("DELETE FROM no_votes WHERE id = ?", (self.vote_id, )) conn.commit() await self.message.delete() await reason(self.discord_id, interaction) @discord.ui.button(label="Nein", style=discord.ButtonStyle.grey) async def no(self, button, interaction): embed = discord.Embed( title="Aktion abgebrochen", description="Es wurde nichts gespeichert.\nDeine Nein-Stimme mit dem angegebenen Grund bleibt bestehen.\nWenn du diese löschen möchtest, wähle die Option 'Stimme entfernen'", color=discord.Colour.blurple(), # Pycord provides a class with default colors you can choose from ) await self.message.delete() await interaction.response.send_message(embed=embed, ephemeral=True) async def on_timeout(self): self.clear_items() class no_clicked_but_yes_vote_question(discord.ui.View): discord_id = "" vote_id = "" @discord.ui.button(label="Ja", style=discord.ButtonStyle.green,) async def yes(self, button, interaction): cur.execute("DELETE FROM yes_votes WHERE id = ?", (self.vote_id, )) conn.commit() await self.message.delete() await reason(self.discord_id, interaction) @discord.ui.button(label="Nein", style=discord.ButtonStyle.grey) async def no(self, button, interaction): await self.message.delete() embed = discord.Embed( title="Aktion abgebrochen", description="Es wurde nichts gespeichert.\nDeine Ja-Stimme bleibt bestehen.\nWenn du diese löschen möchtest, wähle die Option 'Stimme entfernen'", color=discord.Colour.blurple(), ) await interaction.response.send_message(embed=embed, ephemeral=True) async def process_no_vote(interaction, select): cur.execute( "SELECT no_votes.reason, recruits.nickname, no_votes.id FROM recruits, no_votes WHERE recruits.discord_id = no_votes.discord_id_recruit AND no_votes.discord_id_voter = ? AND no_votes.discord_id_recruit = ?", (interaction.user.id, select.values[0])) no_vote = cur.fetchall() cur.execute( "SELECT recruits.nickname, yes_votes.id FROM recruits, yes_votes WHERE yes_votes.discord_id_voter = ? AND yes_votes.discord_id_recruit = ? AND recruits.discord_id = yes_votes.discord_id_recruit", (interaction.user.id, select.values[0])) yes_vote = cur.fetchall() if yes_vote: yes_question_inst = no_clicked_but_yes_vote_question() yes_question_inst.discord_id = select.values[0] # Discord-ID des Rekruten yes_question_inst.vote_id = yes_vote[0][1] embed = discord.Embed( title="Du hast bereits dem Rekruten eine Ja-Stimme gegeben.", description="Möchtest du diese Stimme löschen und eine Nein-Stimme abgeben?", color=discord.Colour.red(), ) embed.add_field(name="Rekrut", value=yes_vote[0][0]) await interaction.response.send_message(embed=embed, view=yes_question_inst, ephemeral=True) elif no_vote: no_question_inst = no_question() no_question_inst.discord_id = select.values[0] no_question_inst.vote_id = no_vote[0][2] embed = discord.Embed( title="Du hast bereits für den Rekruten abgestimmt.", description="Möchtest du deine jetzige Stimme löschen und einen neuen Grund angeben?", color=discord.Colour.blurple(), # Pycord provides a class with default colors you can choose from ) embed.add_field(name="Rekrut", value=no_vote[0][1]) embed.add_field(name="Angegebener Grund", value=no_vote[0][0]) await interaction.response.send_message(embed=embed, view=no_question_inst, ephemeral=True) else: await reason(select.values[0], interaction) class No_select25(discord.ui.View): def __init__(self): super().__init__(timeout=None) # timeout of the view must be set to None @discord.ui.select( custom_id="no25", placeholder="Rekruten wählen...", min_values=1, max_values=1, options=build_option_list()[0] ) async def select_callback(self, select, interaction): # the function called when the user is done selecting options await process_no_vote(interaction, select) class No_select50(discord.ui.View): def __init__(self): super().__init__(timeout=None) # timeout of the view must be set to None @discord.ui.select( custom_id="no50_1", placeholder="Rekruten wählen...", min_values=1, max_values=1, options=build_option_list()[0], row=1 ) async def no_callback1(self, select, interaction): # the function called when the user is done selecting options await process_no_vote(interaction, select) @discord.ui.select( custom_id="no50_2", placeholder="Rekruten wählen...", min_values=1, max_values=1, options=build_option_list(2)[0], row=2 ) async def no_callback2(self, select, interaction): # the function called when the user is done selecting options await process_no_vote(interaction, select) def create_no_embed(): embed = discord.Embed( title="Rekrutenbesichtigung: Nein-Stimme", description="Geb hier deine Nein-Stimme für einen Rekruten ab!", color=discord.Colour.red(), ) return embed async def send_no_message(channel): if get_count_recruits(1) <= 25: message = await channel.send(embed=create_no_embed(), view=no_select_inst25) cur.execute("UPDATE settings SET VALUE = ? WHERE name = 'message_voting_no'", (message.id, )) else: message = await channel.send(embed=create_no_embed(), view=no_select_inst50) cur.execute("UPDATE settings SET VALUE = ? WHERE name = 'message_voting_no'", (message.id, )) async def edit_no_message(): cur.execute("SELECT value FROM settings WHERE name='channel_voting'") channel = bot.get_channel(int(cur.fetchone()[0])) cur.execute("SELECT value FROM settings WHERE name='message_voting_no'") message = await channel.fetch_message(int(cur.fetchone()[0])) conn.commit() if get_count_recruits(1) <= 25: global no_select_inst25 no_select_inst25.children[0].options = build_option_list()[0] await message.edit(embed=create_no_embed(), view=no_select_inst25) else: global no_select_inst50 no_select_inst50.children[0].options = build_option_list()[0] no_select_inst50.children[1].options = build_option_list()[0] await message.edit(embed=create_no_embed(), view=no_select_inst50) class delete_and_view_votes_message(discord.ui.View): def __init__(self): super().__init__(timeout=None) # timeout of the view must be set to None @discord.ui.button(label="Stimmen einsehen", custom_id="show-votes", style=discord.ButtonStyle.grey,) async def view_votes(self, button, interaction): embed = discord.Embed( title="Deine Votes", description="Hier sind deine Ja- und Nein-Stimmen aufgelistet:", color=discord.Colour.blurple(), ) cur.execute("SELECT recruits.nickname FROM recruits, yes_votes WHERE recruits.discord_id = yes_votes.discord_id_recruit AND recruits.recruit = 1 AND yes_votes.discord_id_voter = ?", (interaction.user.id, )) yes_votes = cur.fetchall() cur.execute("SELECT recruits.nickname, no_votes.reason FROM recruits, no_votes WHERE recruits.discord_id = no_votes.discord_id_recruit AND recruits.recruit = 1 AND no_votes.discord_id_voter = ?", (interaction.user.id, )) no_votes = cur.fetchall() if yes_votes: yes_message = "" for vote in yes_votes: yes_message = yes_message + vote[0] + "\n" embed.add_field(name="Ja-Stimmen:", value=yes_message) if no_votes: no_message = "" for vote in no_votes: no_message = no_message + vote[0] + ': "' + vote[1] + '"' + "\n" embed.add_field(name="Nein-Stimmen:", value=no_message) if not yes_votes: if not no_votes: embed.description="Du hast keine Stimmen abgeben! Zock mit den Rekruten und fang an!" embed.set_footer(text="Wenn du denkst, dass dies nicht korrekt ist, wende dich bitte an LordofAgents.") await interaction.response.send_message(embed=embed, ephemeral=True) async def on_timeout(self): self.clear_items() @discord.ui.button(label="Stimme auswählen und löschen", custom_id="delete-votes", style=discord.ButtonStyle.secondary) async def delete_votes(self, button, interaction): cur.execute("SELECT count(yes_votes.id) FROM recruits, yes_votes WHERE recruits.discord_id = yes_votes.discord_id_recruit AND recruits.recruit = 1 AND yes_votes.discord_id_voter = ?", (interaction.user.id,)) yes_votes = cur.fetchone()[0] cur.execute("SELECT count(no_votes.id) FROM recruits, no_votes WHERE recruits.discord_id = no_votes.discord_id_recruit AND recruits.recruit = 1 AND no_votes.discord_id_voter = ?", (interaction.user.id,)) no_votes = cur.fetchone()[0] count = yes_votes + no_votes if count == 0: embed = discord.Embed( title="Keine Stimmen gefunden.", description="Du hast keine Stimmen abgeben! Zock mit den Rekruten und fang an!", color=discord.Colour.blurple(), # Pycord provides a class with default colors you can choose from ) embed.set_footer(text="Wenn du denkst, dass dies nicht korrekt ist, wende dich bitte an LordofAgents.") await interaction.response.send_message(embed=embed, ephemeral=True) elif count <= 25: embed = discord.Embed( title="Stimme löschen", description="Wähle einen Rekruten aus, um deine Stimme für ihn zu löschen", color=discord.Colour.blurple(), # Pycord provides a class with default colors you can choose from ) delete_recruit_vote_inst = delete_recruit_vote25() delete_recruit_vote_inst.children[0].options = getvotes(interaction.user.id) await interaction.response.send_message(embed=embed, view=delete_recruit_vote_inst, ephemeral=True) else: embed = discord.Embed( title="Stimme löschen", description="Wähle einen Rekruten aus, um deine Stimme für ihn zu löschen", color=discord.Colour.blurple(), # Pycord provides a class with default colors you can choose from ) delete_recruit_vote_inst = delete_recruit_vote50() delete_recruit_vote_inst.children[0].options = getvotes(interaction.user.id) delete_recruit_vote_inst.children[1].options = getvotes(interaction.user.id, 2) await interaction.response.send_message(embed=embed, view=delete_recruit_vote_inst, ephemeral=True) def getvotes(voterid, part = 1): cur.execute("SELECT count(*) FROM yes_votes WHERE discord_id_voter = ?", (voterid, )) yes_vote_count = cur.fetchone()[0] cur.execute("SELECT count(*) FROM no_votes WHERE discord_id_voter = ?", (voterid,)) no_vote_count = cur.fetchone()[0] count = yes_vote_count + no_vote_count cur.execute( "SELECT recruits.discord_id, recruits.nickname FROM recruits, yes_votes WHERE recruits.discord_id = yes_votes.discord_id_recruit AND yes_votes.discord_id_voter = ? AND recruit = 1", (voterid, )) yes_votes = cur.fetchall() option = [] new_option = [] if count <= 25: for vote in yes_votes: option.append(discord.SelectOption(value=str(vote[0]), label="Ja: " + str(vote[1]))) cur.execute( "SELECT recruits.discord_id, recruits.nickname FROM recruits, no_votes WHERE recruits.discord_id = no_votes.discord_id_recruit AND no_votes.discord_id_voter = ? AND recruit = 1", (voterid, )) no_votes = cur.fetchall() for vote in no_votes: option.append(discord.SelectOption(value=str(vote[0]), label="Nein: " + str(vote[1]))) return option else: for vote in yes_votes: option.append(discord.SelectOption(value=str(vote[0]), label="Ja: " + str(vote[1]))) cur.execute( "SELECT recruits.discord_id, recruits.nickname FROM recruits, no_votes WHERE recruits.discord_id = no_votes.discord_id_recruit AND no_votes.discord_id_voter = ? AND recruit = 1", (voterid, )) no_votes = cur.fetchall() for vote in no_votes: option.append(discord.SelectOption(value=str(vote[0]), label="Nein: " + str(vote[1]))) if part == 1: count = 0 for option_single in option: if count >= 25: break else: new_option.append(option_single) count = count + 1 return new_option else: count = 0 for option_single in option: if count < 25: count = count + 1 continue else: new_option.append(option_single) count = count + 1 return new_option async def process_deletion_request(select, interaction): confirm_deletion_of_vote_inst = confirm_deletion_of_vote() confirm_deletion_of_vote.votes = select.values description = "Du möchtest deine Stimme für folgenden Rekruten löschen:\n" for choice in select.values: cur.execute("SELECT nickname FROM recruits WHERE discord_id = ?", (choice,)) nickname = cur.fetchone()[0] description = description + nickname + "\n" embed = discord.Embed( title="Stimme löschen", description=description, color=discord.Colour.blurple(), # Pycord provides a class with default colors you can choose from ) await interaction.response.send_message(embed=embed, view=confirm_deletion_of_vote_inst, ephemeral=True) class delete_recruit_vote25(discord.ui.View): @discord.ui.select( placeholder = "Rekruten auswählen...", min_values = 1, max_values = 1, # the maximum number of values that can be selected by the users options = [] ) async def select_callback(self, select, interaction): # the function called when the user is done selecting options await process_deletion_request(select, interaction) await self.message.delete() async def on_timeout(self): self.clear_items() class delete_recruit_vote50(discord.ui.View): @discord.ui.select( placeholder = "Rekruten auswählen...", min_values = 1, max_values = 1, # the maximum number of values that can be selected by the users options = [] ) async def select1(self, select, interaction): # the function called when the user is done selecting options await process_deletion_request(select, interaction) await self.message.delete() @discord.ui.select( placeholder = "Rekruten auswählen...", min_values = 1, max_values = 1, # the maximum number of values that can be selected by the users options = [] ) async def select2(self, select, interaction): # the function called when the user is done selecting options await process_deletion_request(select, interaction) await self.message.delete() async def on_timeout(self): self.clear_items() class confirm_deletion_of_vote(discord.ui.View): # Create a class called MyView that subclasses discord.ui.View votes = [] @discord.ui.button(label="Stimme löschen", style=discord.ButtonStyle.danger) async def ja(self, button, interaction): for vote in self.votes: cur.execute("DELETE FROM yes_votes WHERE discord_id_voter = ? AND discord_id_recruit = ?", (interaction.user.id, vote)) cur.execute("DELETE FROM no_votes WHERE discord_id_voter = ? AND discord_id_recruit = ?", (interaction.user.id, vote)) conn.commit() embed = discord.Embed( title="Löschvorgang abgeschlossen", description="Deine Stimmen wurden gelöscht. \nSollte das ein Fehler sein, stimme einfach erneut ab.", color=discord.Colour.green(), ) await interaction.response.send_message(embed=embed, ephemeral=True) await edit_report_message() await self.message.delete() @discord.ui.button(label="Abbrechen", style=discord.ButtonStyle.secondary) async def nein(self, button, interaction): embed = discord.Embed( title="Löschvorgang abgebrochen", description="Deine Stimmen wurden nicht modifiziert.", color=discord.Colour.dark_red(), ) await interaction.response.send_message(embed=embed, ephemeral=True) await self.message.delete() async def on_timeout(self): self.clear_items() async def send_delete_message(channel): embed = discord.Embed( title="Stimmen einsehen oder löschen", description="Um deine Stimmene einzusehen oder eine Stimme zu löschen, klicke auf den entsprechenden Button.", color=discord.Colour.dark_red(), ) message = await channel.send(embed=embed, view=delete_and_view_votes_message()) cur.execute("UPDATE settings SET VALUE = ? WHERE name = 'message_delete_vote'", (message.id, )) async def process_detailed_report(select, interaction): cur.execute("SELECT nickname FROM recruits WHERE discord_id = ?", (select.values[0],)) nick = cur.fetchone()[0] embed = discord.Embed( title="Abstimmungen für " + nick, color=discord.Colour.blurple(), # Pycord provides a class with default colors you can choose from ) cur.execute("SELECT discord_id_voter FROM yes_votes WHERE discord_id_recruit = ?", (select.values[0],)) yes_votes = cur.fetchall() yes_vote = "" cur.execute("SELECT value FROM settings WHERE name = ?", ("guild",)) guild_id = cur.fetchone()[0] guild = bot.get_guild(guild_id) for vote in yes_votes: yes_vote = yes_vote + guild.get_member(vote[0]).display_name + "\n" cur.execute("SELECT count(*) FROM yes_votes WHERE discord_id_recruit = ?", (select.values[0],)) count_yes_votes = cur.fetchone()[0] embed.add_field(name="Ja-Stimmen (" + str(count_yes_votes) + "):", value=yes_vote) cur.execute("SELECT discord_id_voter, reason FROM no_votes WHERE discord_id_recruit = ?", (select.values[0],)) no_votes = cur.fetchall() no_vote_text = "" for vote in no_votes: no_vote_text = no_vote_text + "**" + guild.get_member(vote[0]).display_name + "**: " + vote[1] + "\n" cur.execute("SELECT count(*) FROM no_votes WHERE discord_id_recruit = ?", (select.values[0],)) count_no_votes = cur.fetchone()[0] embed.add_field(name="Nein-Stimmen (" + str(count_no_votes) + "):", value=no_vote_text) await interaction.response.send_message(embed=embed, ephemeral=True) @settings.command(description="Sendet die Nachricht zum Abstimmen in den aktuellen Channel.") @default_permissions(manage_roles=True) async def message_voting(ctx): cur.execute("UPDATE settings SET VALUE = ? WHERE name = 'channel_voting'", (ctx.channel_id, )) await send_yes_message(ctx.channel) await send_no_message(ctx.channel) await send_delete_message(ctx.channel) conn.commit() await ctx.respond(f"Done.", ephemeral=True) class report_select_menu25(discord.ui.View): @discord.ui.select( # the decorator that lets you specify the properties of the select menu placeholder = "Rekruten wählen...", # the placeholder text that will be displayed if nothing is selected min_values = 1, # the minimum number of values that must be selected by the users max_values = 1, # the maximum number of values that can be selected by the users options = build_option_list()[0] ) async def select_callback(self, select, interaction): await self.message.delete() await process_detailed_report(select, interaction) async def on_timeout(self): self.clear_items() class report_select_menu50(discord.ui.View): @discord.ui.select( # the decorator that lets you specify the properties of the select menu placeholder = "Rekruten wählen...", # the placeholder text that will be displayed if nothing is selected min_values = 1, # the minimum number of values that must be selected by the users max_values = 1, # the maximum number of values that can be selected by the users options = build_option_list()[0], row=1 ) async def select1(self, select, interaction): await self.message.delete() await process_detailed_report(select, interaction) @discord.ui.select( # the decorator that lets you specify the properties of the select menu placeholder = "Rekruten wählen...", # the placeholder text that will be displayed if nothing is selected min_values = 1, # the minimum number of values that must be selected by the users max_values = 1, # the maximum number of values that can be selected by the users options = build_option_list()[1], row=2 ) async def select2(self, select, interaction): await self.message.delete() await process_detailed_report(select, interaction) async def on_timeout(self): self.clear_items() class generate_report25(discord.ui.View): @discord.ui.select( # the decorator that lets you specify the properties of the select menu placeholder="Rekruten wählen...", # the placeholder text that will be displayed if nothing is selected min_values=1, # the minimum number of values that must be selected by the users max_values=get_count_recruits(), # the maximum number of values that can be selected by the users options=[] ) async def select_callback(self, select, interaction): await interaction.response.defer(ephemeral=True) embed = discord.Embed( title="Rekrutenbesichtigung: Erstellter Report", color=discord.Colour.blurple(), # Pycord provides a class with default colors you can choose from ) description = "```\n" guild = interaction.guild for recruit in select.values: cur.execute("SELECT recruits.nickname, count(yes_votes.id), count(no_votes.id) FROM recruits LEFT JOIN no_votes ON recruits.discord_id = no_votes.discord_id_recruit LEFT JOIN yes_votes ON recruits.discord_id = yes_votes.discord_id_recruit WHERE recruits.discord_id = ?", (recruit, )) data = cur.fetchone() description = description + "**" + data[0] + ":** " + data[1] + " Ja | " + data[2] + "Nein -> \n" if data[1] != 0: cur.execute("SELECT discord_id_voter, reason FROM no_votes WHERE discord_id_recruit = ?", (recruit, )) no_votes = cur.fetchall() for vote in no_votes: nick = guild.get_member(vote[0]).display_name description = description + "Begründung von " + nick + ": " + vote[1] + "\n" description = description + "\n\n" embed.description = description await interaction.followup.send(embed=embed, ephemeral=True) class report_buttons(discord.ui.View): def __init__(self): super().__init__(timeout=None) @discord.ui.button(label="Auswertung pro Rekrut", style=discord.ButtonStyle.primary, row=1, custom_id="report_buttons_pro_person") async def report_per_recruit(self, button, interaction): embed = discord.Embed( title="Bitte wähle einen Rekruten aus", color=discord.Colour.blurple(), # Pycord provides a class with default colors you can choose from ) if get_count_recruits(1) <= 25: report_select_menu25_inst = report_select_menu25() report_select_menu25_inst.children[0].options = build_option_list(1)[0] await interaction.response.send_message(embed=embed, view=report_select_menu25_inst, ephemeral=True) else: report_select_menu50_inst = report_select_menu50() report_select_menu50_inst.children[0].options = build_option_list(1)[0] report_select_menu50_inst.children[1].options = build_option_list(2)[0] await interaction.response.send_message(embed=embed, view=report_select_menu50_inst, ephemeral=True) @discord.ui.button(label="Rekrutenbesichtigung generieren", style=discord.ButtonStyle.primary, row=1, custom_id="report_buttons_checkout") async def checkout_recruits(self, button, interaction): generate_report25_inst = generate_report25() generate_report25_inst.children[0].options = build_option_list()[0] embed = discord.Embed( title="Rekrut wählen", description="Bitte wähle einen oder mehrere Rekruten aus", color=discord.Colour.blurple(), # Pycord provides a class with default colors you can choose from ) await interaction.response.send_message(embed=embed, view=generate_report25_inst, ephemeral=True) @discord.ui.button(label="Daten aktualisieren", style=discord.ButtonStyle.secondary, row=2, custom_id="report_buttons_refresh") async def refresh_button(self, button, interaction): await interaction.response.send_message(content="Refresh angestoßen! Dies dauert einen kleinen Moment.", ephemeral=True) await process_refresh() def create_report_embed(): embed = discord.Embed( title="Aktuelle Stimmen", color=discord.Colour.blurple(), # Pycord provides a class with default colors you can choose from ) cur.execute("SELECT recruits.nickname, count(yes_votes.id), count(no_votes.id), recruits.discord_id FROM recruits LEFT JOIN no_votes ON recruits.discord_id = no_votes.discord_id_recruit LEFT JOIN yes_votes ON recruits.discord_id = yes_votes.discord_id_recruit WHERE recruits.recruit = 1 GROUP BY recruits.nickname") recruits = cur.fetchall() description = "" cur.execute("SELECT value FROM settings WHERE name = ?", ("guild", )) guild_id = cur.fetchone()[0] guild = bot.get_guild(guild_id) for recruit in recruits: if recruit[2] != 0: cur.execute("SELECT reason, discord_id_voter FROM no_votes WHERE discord_id_recruit = ?", (recruit[3], )) no_votes = cur.fetchall() description = description + "**" + recruit[0] + ":** " + str(recruit[1]) + " Ja, " + str(recruit[2]) + " Nein.\n" for no_vote in no_votes: description = description + "Begründung von " + guild.get_member(no_vote[1]).display_name + ": " + no_vote[0] + "\n" description = description + "\n\n" else: description = description + "**" + recruit[0] + ":** " + str(recruit[1]) + " Ja, " + str(recruit[2]) + " Nein.\n" embed.description = description return embed @settings.command(description="Sendet den Report in den aktuellen Kanal.") @default_permissions(manage_roles=True) async def message_report(ctx): cur.execute("UPDATE settings SET VALUE = ? WHERE name = 'channel_report'", (ctx.channel_id, )) channel = ctx.channel message = await channel.send(embed=create_report_embed(), view=report_buttons()) cur.execute("UPDATE settings SET VALUE = ? WHERE name = 'message_report'", (message.id, )) conn.commit() await ctx.respond(f"Done.", ephemeral=True) @settings.command(description="Setzt die ID der Rekruten-Rolle") @default_permissions(manage_roles=True) async def role_recruit( ctx, rolearg: discord.Option(discord.SlashCommandOptionType.role) ): cur.execute("UPDATE settings SET VALUE = ? WHERE name = 'role_recruit'", (rolearg.id, )) conn.commit() await ctx.respond(f"Done.", ephemeral=True) @settings.command(description="Setzt den Discord-Server") @default_permissions(manage_roles=True) async def guild(ctx): cur.execute("UPDATE settings SET VALUE = ? WHERE name = 'guild'", (ctx.guild_id, )) conn.commit() await ctx.respond(f"Done.", ephemeral=True) def check_roles(member, recruit_id): for role in member.roles: if role.id == recruit_id: return "Yes" async def process_refresh(): cur.execute("SELECT value FROM settings WHERE name='guild'") guild_id = cur.fetchone() guild_id = guild_id[0] cur.execute("SELECT value FROM settings WHERE name='role_recruit'") recruit_id = cur.fetchone()[0] guild = bot.get_guild(guild_id) for role in guild.roles: if role.id == recruit_id: for member in role.members: recruit_update(member, 1, cur, conn) for member in guild.members: result = check_roles(member, recruit_id) if result == "Yes": pass else: cur.execute("UPDATE recruits SET recruit = ?, nickname = ? WHERE discord_id = ?", (0, member.display_name, member.id)) conn.commit() cur.execute("SELECT discord_id FROM recruits WHERE recruit = 1") recruits = cur.fetchall() for recruit in recruits: member = guild.get_member(recruit[0]) if member is None: cur.execute("UPDATE recruits SET recruit = 0 WHERE discord_id = ?", (recruit[0],)) conn.commit() await edit_yes_message() await edit_no_message() await edit_report_message() async def edit_report_message(): cur.execute("SELECT value FROM settings WHERE name='channel_report'") channel = bot.get_channel(int(cur.fetchone()[0])) cur.execute("SELECT value FROM settings WHERE name='message_report'") message = await channel.fetch_message(int(cur.fetchone()[0])) await message.edit(embed=create_report_embed(), view=report_buttons()) @settings.command(description="Aktualisiert die internen Daten.") @default_permissions(manage_roles=True) async def refresh(ctx): await ctx.defer(ephemeral=True) await process_refresh() await ctx.respond(f"Refresh angestoßen! Dies dauert einen kleinen Moment.", ephemeral=True) @bot.event async def on_member_update(previous, after): cur.execute("SELECT value FROM settings WHERE name='role_recruit'") recruit_id = cur.fetchone() recruit_id = recruit_id[0] found = False for role in after.roles: if role.id == recruit_id: recruit_update(after, 1, cur, conn) found = True break if found: pass # Kein Rekrut else: for role in previous.roles: if role.id == recruit_id: recruit_update(after, 0, cur, conn) break await edit_yes_message() await edit_no_message() await edit_report_message() bot.run(os.getenv('TOKEN')) # run the bot with the token