Untitled

 avatar
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