Untitled
unknown
python
a year ago
17 kB
5
Indexable
import discord from discord.ext import commands, tasks import sqlite3 import asyncio import datetime import os from io import StringIO import html # Konfiguration TICKET_CATEGORY_ID = 1234149548192956457 TICKET_HANDLER_ROLE_ID = 1063979839478042624 PRIORITY_CHANNEL_ID = 1243627826851352666 TRANSCRIPT_CHANNEL_ID = 1245290800544219146 DATABASE_PATH = './database/tickets.db' def setup_database(): conn = sqlite3.connect(DATABASE_PATH) c = conn.cursor() c.execute('''CREATE TABLE IF NOT EXISTS tickets (id INTEGER PRIMARY KEY AUTOINCREMENT, channel_id INTEGER, user_id INTEGER, handler_id INTEGER, reason TEXT, status TEXT, created_at DATETIME, closed_at DATETIME, last_activity DATETIME)''') conn.commit() conn.close() class TicketView(discord.ui.View): def __init__(self): super().__init__(timeout=None) @discord.ui.button(label="Guide-Ticket erstellen", style=discord.ButtonStyle.green, custom_id="create_guide_ticket") async def create_ticket(self, button: discord.ui.Button, interaction: discord.Interaction): if await self.user_has_open_ticket(interaction.user.id): await interaction.response.send_message("Du hast bereits ein offenes Ticket.", ephemeral=True) return modal = TicketReasonModal() await interaction.response.send_modal(modal) await modal.wait() if modal.reason: await self.create_ticket_channel(interaction, modal.reason) async def user_has_open_ticket(self, user_id): conn = sqlite3.connect(DATABASE_PATH) c = conn.cursor() c.execute("SELECT COUNT(*) FROM tickets WHERE user_id = ? AND status = 'open'", (user_id,)) count = c.fetchone()[0] conn.close() return count > 0 async def create_ticket_channel(self, interaction, reason): guild = interaction.guild category = guild.get_channel(TICKET_CATEGORY_ID) ticket_handler_role = guild.get_role(TICKET_HANDLER_ROLE_ID) overwrites = { guild.default_role: discord.PermissionOverwrite(read_messages=False), interaction.user: discord.PermissionOverwrite(read_messages=True, send_messages=True), ticket_handler_role: discord.PermissionOverwrite(read_messages=True, send_messages=True), guild.me: discord.PermissionOverwrite(read_messages=True, send_messages=True, manage_channels=True) } channel = await category.create_text_channel(f"guide-ticket-{interaction.user.name}", overwrites=overwrites) conn = sqlite3.connect(DATABASE_PATH) c = conn.cursor() c.execute("INSERT INTO tickets (channel_id, user_id, reason, status, created_at, last_activity) VALUES (?, ?, ?, ?, ?, ?)", (channel.id, interaction.user.id, reason, 'open', datetime.datetime.now(), datetime.datetime.now())) conn.commit() conn.close() embed = discord.Embed(title="Neues Guide-Ticket", description=f"Erstellt von {interaction.user.mention}\nGrund: {reason}", color=discord.Color.green()) await channel.send(embed=embed, view=TicketManagementView()) await channel.send(f"{interaction.user.mention} {ticket_handler_role.mention}") await interaction.followup.send(f"Dein Guide-Ticket wurde erstellt: {channel.mention}", ephemeral=True) class TicketReasonModal(discord.ui.Modal): def __init__(self): super().__init__(title="Grund für das Guide-Ticket") self.reason = None self.add_item(discord.ui.InputText(label="Grund", style=discord.InputTextStyle.paragraph)) async def callback(self, interaction: discord.Interaction): self.reason = self.children[0].value await interaction.response.defer() class TicketManagementView(discord.ui.View): def __init__(self): super().__init__(timeout=None) @discord.ui.button(label="schließen", style=discord.ButtonStyle.red, custom_id="close_ticket") async def close_ticket(self, button: discord.ui.Button, interaction: discord.Interaction): if interaction.user.get_role(TICKET_HANDLER_ROLE_ID): await self.close_ticket_channel(interaction) else: await interaction.response.send_message("Du hast keine Berechtigung, das Ticket zu schließen.", ephemeral=True) @discord.ui.button(label="beanspruchen", style=discord.ButtonStyle.green, custom_id="claim_ticket") async def claim_ticket(self, button: discord.ui.Button, interaction: discord.Interaction): if interaction.user.get_role(TICKET_HANDLER_ROLE_ID): await self.claim_ticket_channel(interaction) else: await interaction.response.send_message("Du hast keine Berechtigung, das Ticket zu beanspruchen.", ephemeral=True) @discord.ui.button(label="freigeben", style=discord.ButtonStyle.gray, custom_id="release_ticket") async def release_ticket(self, button: discord.ui.Button, interaction: discord.Interaction): if interaction.user.get_role(TICKET_HANDLER_ROLE_ID): await self.release_ticket_channel(interaction) else: await interaction.response.send_message("Du hast keine Berechtigung, das Ticket freizugeben.", ephemeral=True) @discord.ui.button(label="priorität erhöhen", style=discord.ButtonStyle.blurple, custom_id="increase_priority") async def increase_priority(self, button: discord.ui.Button, interaction: discord.Interaction): await self.increase_ticket_priority(interaction) @discord.ui.button(label="ticket übertragen", style=discord.ButtonStyle.gray, custom_id="transfer_ticket") async def transfer_ticket(self, button: discord.ui.Button, interaction: discord.Interaction): if interaction.user.get_role(TICKET_HANDLER_ROLE_ID): await self.transfer_ticket_channel(interaction) else: await interaction.response.send_message("Du hast keine Berechtigung, das Ticket zu übertragen.", ephemeral=True) async def close_ticket_channel(self, interaction): conn = sqlite3.connect(DATABASE_PATH) c = conn.cursor() c.execute("UPDATE tickets SET status = 'closed', closed_at = ? WHERE channel_id = ?", (datetime.datetime.now(), interaction.channel.id)) conn.commit() conn.close() transcript = await self.create_transcript(interaction.channel) transcript_channel = interaction.guild.get_channel(TRANSCRIPT_CHANNEL_ID) file = discord.File(StringIO(transcript), filename=f"transcript-{interaction.channel.name}.html") await transcript_channel.send(f"Transcript für {interaction.channel.mention}", file=file) user_id = await self.get_ticket_user(interaction.channel.id) user = interaction.guild.get_member(user_id) if user: await self.send_rating_form(user) await interaction.channel.delete() async def claim_ticket_channel(self, interaction): conn = sqlite3.connect(DATABASE_PATH) c = conn.cursor() c.execute("UPDATE tickets SET handler_id = ? WHERE channel_id = ?", (interaction.user.id, interaction.channel.id)) conn.commit() conn.close() await interaction.channel.set_permissions(interaction.user, send_messages=True) await interaction.channel.set_permissions(interaction.guild.get_role(TICKET_HANDLER_ROLE_ID), send_messages=False) await interaction.response.send_message(f"{interaction.user.mention} hat dieses Ticket beansprucht.") async def release_ticket_channel(self, interaction): conn = sqlite3.connect(DATABASE_PATH) c = conn.cursor() c.execute("UPDATE tickets SET handler_id = NULL WHERE channel_id = ?", (interaction.channel.id,)) conn.commit() conn.close() await interaction.channel.set_permissions(interaction.guild.get_role(TICKET_HANDLER_ROLE_ID), send_messages=True) await interaction.response.send_message(f"{interaction.user.mention} hat dieses Ticket freigegeben.") async def increase_ticket_priority(self, interaction): priority_channel = interaction.guild.get_channel(PRIORITY_CHANNEL_ID) await priority_channel.send(f"<@&{TICKET_HANDLER_ROLE_ID}> Das Ticket {interaction.channel.mention} benötigt dringende Bearbeitung!") await interaction.response.send_message("Die Priorität des Tickets wurde erhöht.") async def transfer_ticket_channel(self, interaction): modal = TicketTransferModal() await interaction.response.send_modal(modal) await modal.wait() if modal.transfer_to: member = interaction.guild.get_member_named(modal.transfer_to) if member and member.get_role(TICKET_HANDLER_ROLE_ID): conn = sqlite3.connect(DATABASE_PATH) c = conn.cursor() c.execute("UPDATE tickets SET handler_id = ? WHERE channel_id = ?", (member.id, interaction.channel.id)) conn.commit() conn.close() await interaction.channel.set_permissions(member, send_messages=True) await interaction.channel.set_permissions(interaction.user, send_messages=False) await interaction.followup.send(f"Das Ticket wurde an {member.mention} übertragen.") await member.send(f"Das Ticket {interaction.channel.mention} wurde an dich übertragen.") else: await interaction.followup.send("Der angegebene Benutzer wurde nicht gefunden oder hat nicht die erforderliche Rolle.", ephemeral=True) async def create_transcript(self, channel): messages = await channel.history(limit=None).flatten() transcript = "<html><head><style>body{font-family:Arial,sans-serif;} .message{margin-bottom:10px;} .author{font-weight:bold;}</style></head><body>" for message in reversed(messages): transcript += f"<div class='message'><span class='author'>{html.escape(message.author.name)}:</span> {html.escape(message.content)}</div>" transcript += "</body></html>" return transcript async def get_ticket_user(self, channel_id): conn = sqlite3.connect(DATABASE_PATH) c = conn.cursor() c.execute("SELECT user_id FROM tickets WHERE channel_id = ?", (channel_id,)) user_id = c.fetchone()[0] conn.close() return user_id async def send_rating_form(self, user): embed = discord.Embed(title="Ticket-Bewertung", description="Bitte bewerte deine Erfahrung mit diesem Ticket.") view = RatingView(self.bot) await user.send(embed=embed, view=view) class TicketTransferModal(discord.ui.Modal): def __init__(self): super().__init__(title="Ticket übertragen") self.transfer_to = None self.add_item(discord.ui.InputText(label="Übertragen an (Benutzername#Diskriminator)")) async def callback(self, interaction: discord.Interaction): self.transfer_to = self.children[0].value await interaction.response.defer() class TicketCog(commands.Cog): def __init__(self, bot): self.bot = bot self.check_inactivity.start() def cog_unload(self): self.check_inactivity.cancel() @commands.Cog.listener() async def on_ready(self): print(f"Ticket-System ist bereit. Überprüfe bestehende Tickets...") await self.setup_existing_tickets() @commands.Cog.listener() async def on_message(self, message): if isinstance(message.channel, discord.TextChannel) and message.channel.category_id == TICKET_CATEGORY_ID: conn = sqlite3.connect(DATABASE_PATH) c = conn.cursor() c.execute("UPDATE tickets SET last_activity = ? WHERE channel_id = ?", (datetime.datetime.now(), message.channel.id)) conn.commit() conn.close() @commands.slash_command(name="ticketsetup", description="Richtet das Ticket-System ein") @commands.has_permissions(administrator=True) async def ticket_setup(self, ctx): embed = discord.Embed(title="Guide-Ticket System", description="Klicke auf den Button, um ein Guide-Ticket zu erstellen.") await ctx.send(embed=embed, view=TicketView()) @commands.slash_command(name="tickettrack", description="Zeigt die Anzahl der bearbeiteten Guide-Tickets in den letzten zwei Wochen") async def ticket_track(self, ctx): two_weeks_ago = datetime.datetime.now() - datetime.timedelta(weeks=2) conn = sqlite3.connect(DATABASE_PATH) c = conn.cursor() c.execute("SELECT COUNT(*) FROM tickets WHERE closed_at > ? AND status = 'closed'", (two_weeks_ago,)) count = c.fetchone()[0] conn.close() await ctx.respond(f"In den letzten zwei Wochen wurden {count} Guide-Tickets bearbeitet.") @tasks.loop(minutes=5) async def check_inactivity(self): now = datetime.datetime.now() conn = sqlite3.connect(DATABASE_PATH) c = conn.cursor() c.execute("SELECT channel_id, user_id, handler_id, last_activity FROM tickets WHERE status = 'open'") tickets = c.fetchall() for channel_id, user_id, handler_id, last_activity in tickets: last_activity = datetime.datetime.fromisoformat(last_activity) if now - last_activity > datetime.timedelta(hours=3): await self.remind_ticket(channel_id, user_id, handler_id) elif now - last_activity > datetime.timedelta(days=1): await self.auto_close_ticket(channel_id, user_id, handler_id) conn.close() async def remind_ticket(self, channel_id, user_id, handler_id): channel = self.bot.get_channel(channel_id) if channel: mentions = [f"<@{user_id}>"] if handler_id: mentions.append(f"<@{handler_id}>") else: mentions.append(f"<@&{TICKET_HANDLER_ROLE_ID}>") await channel.send(f"{' '.join(mentions)} Dieses Ticket ist seit 3 Stunden inaktiv. Bitte setzt die Bearbeitung fort.") async def auto_close_ticket(self, channel_id, user_id, handler_id): channel = self.bot.get_channel(channel_id) if channel: await channel.send("Dieses Ticket wird aufgrund von Inaktivität geschlossen.") await self.close_ticket_channel(channel) user = self.bot.get_user(user_id) if user: await user.send("Dein Ticket wurde aufgrund von Inaktivität geschlossen.") if handler_id: handler = self.bot.get_user(handler_id) if handler: await handler.send(f"Das von dir beanspruchte Ticket in {channel.name} wurde aufgrund von Inaktivität geschlossen.") async def setup_existing_tickets(self): conn = sqlite3.connect(DATABASE_PATH) c = conn.cursor() c.execute("SELECT channel_id FROM tickets WHERE status = 'open'") open_tickets = c.fetchall() conn.close() for channel_id in open_tickets: channel = self.bot.get_channel(channel_id[0]) if channel: await channel.send("Der Bot wurde neugestartet. Das Ticket-Management wurde wiederhergestellt.", view=TicketManagementView()) else: print(f"Kanal mit ID {channel_id[0]} nicht gefunden. Möglicherweise wurde er gelöscht.") class RatingView(discord.ui.View): def __init__(self, bot): super().__init__(timeout=None) self.bot = bot @discord.ui.select( placeholder="Wähle eine Bewertung", options=[discord.SelectOption(label=str(i), value=str(i)) for i in range(1, 6)] ) async def select_rating(self, select: discord.ui.Select, interaction: discord.Interaction): rating = int(select.values[0]) await interaction.response.send_modal(FeedbackModal(rating)) class FeedbackModal(discord.ui.Modal): def __init__(self, rating): super().__init__(title=f"Feedback für {rating}-Sterne Bewertung") self.rating = rating self.feedback = discord.ui.InputText(label="Dein Feedback", style=discord.InputTextStyle.long) self.add_item(self.feedback) async def callback(self, interaction: discord.Interaction): feedback = self.feedback.value transcript_channel = interaction.guild.get_channel(TRANSCRIPT_CHANNEL_ID) embed = discord.Embed(title="Ticket-Bewertung", description=f"Bewertung: {self.rating} Sterne\nFeedback: {feedback}") await transcript_channel.send(embed=embed) await interaction.response.send_message("Vielen Dank für dein Feedback!", ephemeral=True) def setup(bot): setup_database() bot.add_cog(TicketCog(bot))
Editor is loading...
Leave a Comment