Skip to content

Commit

Permalink
Implement Ticket System
Browse files Browse the repository at this point in the history
  • Loading branch information
dkoz committed Nov 14, 2024
1 parent 4dff86f commit a2c10ff
Showing 1 changed file with 228 additions and 0 deletions.
228 changes: 228 additions & 0 deletions cogs/tickets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
import nextcord
from nextcord.ext import commands
from nextcord.ui import Button, View
from nextcord.ext.commands import has_permissions
import utils.constants as constants
import json
import os
from io import StringIO

class TicketSystem(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.data_folder = 'data'
self.config_file = os.path.join(self.data_folder, 'tickets.json')
self.data = self.load_config()
self.ticket_counter = self.data.get('ticket_counter', 1)
self.dm_on_close = self.data.get('dm_on_close', False)
self.transcript_enabled = self.data.get('transcript_enabled', False)
self.bot.loop.create_task(self.setup_buttons())

def load_config(self):
if not os.path.exists(self.config_file):
os.makedirs(self.data_folder, exist_ok=True)
with open(self.config_file, 'w') as f:
json.dump({'ticket_channel_id': None, 'log_channel_id': None, 'buttons': [], 'categories': [], 'ticket_counter': 1, 'dm_on_close': False, 'transcript_enabled': False}, f)
with open(self.config_file, 'r') as f:
return json.load(f)

def save_config(self):
with open(self.config_file, 'w') as f:
json.dump(self.data, f)

async def setup_buttons(self):
await self.bot.wait_until_ready()
ticket_channel_id = self.data.get('ticket_channel_id')
if ticket_channel_id:
channel = self.bot.get_channel(ticket_channel_id)
if channel:
for button_info in self.data.get('buttons', []):
try:
message = await channel.fetch_message(button_info['message_id'])
except (nextcord.NotFound, nextcord.HTTPException):
continue

view = View(timeout=None)
for category in self.data.get('categories', []):
button = Button(label=category, style=nextcord.ButtonStyle.green, custom_id=f"create_ticket_{category}")
button.callback = self.button_callback
view.add_item(button)
await message.edit(view=view)

@commands.group(name="tickets", description="Get list of available ticket commands.", invoke_without_command=True)
@has_permissions(manage_channels=True)
async def tickets(self, ctx):
prefix = ctx.prefix
embed = nextcord.Embed(
title="Ticket System",
description="Commands for setting up the ticket system.",
color=nextcord.Color.orange()
)
embed.add_field(
name="Commands",
value=f"`{prefix}tickets channel` - Set the ticket channel\n"
f"`{prefix}tickets logchannel` - Set the log channel\n"
f"`{prefix}tickets addcategory` - Add a new ticket category\n"
f"`{prefix}tickets removecategory` - Remove a ticket category\n"
f"`{prefix}tickets transcript` - Toggle DM on close and transcript generation."
)
embed.set_footer(text="Still in testing...", icon_url=constants.FOOTER_IMAGE)
await ctx.send(embed=embed)

@tickets.command(name="transcript")
@has_permissions(manage_channels=True)
async def toggle_transcript(self, ctx, dm_on_close: bool, transcript_enabled: bool):
self.data['dm_on_close'] = dm_on_close
self.data['transcript_enabled'] = transcript_enabled
self.save_config()
await ctx.send(f"DM on close set to {dm_on_close}. Transcript generation set to {transcript_enabled}.")

@tickets.command(name="addcategory")
@has_permissions(manage_channels=True)
async def add_category(self, ctx, *, category_name: str):
if 'categories' not in self.data:
self.data['categories'] = []
self.data['categories'].append(category_name)
self.save_config()
await self.update_ticket_message(ctx)
await ctx.send(f"Category '{category_name}' added to the ticket system.")

@tickets.command(name="removecategory")
@has_permissions(manage_channels=True)
async def remove_category(self, ctx, *, category_name: str):
if 'categories' in self.data and category_name in self.data['categories']:
self.data['categories'].remove(category_name)
self.save_config()
await self.update_ticket_message(ctx)
await ctx.send(f"Category '{category_name}' removed from the ticket system.")
else:
await ctx.send(f"Category '{category_name}' does not exist.")

async def update_ticket_message(self, ctx):
ticket_channel_id = self.data.get('ticket_channel_id')
if ticket_channel_id:
ticket_channel = self.bot.get_channel(ticket_channel_id)
if ticket_channel:
for button_info in self.data.get('buttons', []):
if button_info['channel_id'] == ticket_channel_id:
try:
message = await ticket_channel.fetch_message(button_info['message_id'])
await message.delete()
except (nextcord.NotFound, nextcord.HTTPException):
pass

view = View(timeout=None)
for category in self.data['categories']:
button = Button(label=category, style=nextcord.ButtonStyle.green, custom_id=f"create_ticket_{category}")
button.callback = self.button_callback
view.add_item(button)

embed = nextcord.Embed(title="Support Tickets", description="Click a button below to create a new ticket in a specific category.")
message = await ticket_channel.send(embed=embed, view=view)

self.data['buttons'] = [{
'channel_id': ticket_channel.id,
'message_id': message.id,
'categories': self.data['categories']
}]
self.save_config()

@tickets.command(name="channel")
@has_permissions(manage_channels=True)
async def setup_ticket(self, ctx, channel: nextcord.TextChannel):
self.data['ticket_channel_id'] = channel.id
self.save_config()
await self.update_ticket_message(ctx)
await ctx.send(f"Ticket system set up in {channel.mention}")

@tickets.command(name="logchannel")
@has_permissions(manage_channels=True)
async def setup_log(self, ctx, channel: nextcord.TextChannel):
self.data['log_channel_id'] = channel.id
self.save_config()
await ctx.send(f"Ticket log channel set to {channel.mention}")

async def button_callback(self, interaction: nextcord.Interaction):
custom_id = interaction.data.get('custom_id')
if custom_id.startswith("create_ticket_"):
category = custom_id.split("_", 2)[2]
await self.create_ticket(interaction, category)
elif custom_id.startswith("close_ticket_"):
thread_id = int(custom_id.split("_")[-1])
thread = await self.bot.fetch_channel(thread_id)
await self.close_ticket(interaction, thread)

async def create_ticket(self, interaction: nextcord.Interaction, category: str):
member = interaction.user
ticket_channel_id = self.data.get('ticket_channel_id')
if ticket_channel_id:
ticket_channel = self.bot.get_channel(ticket_channel_id)
thread = await ticket_channel.create_thread(name=f"ticket-{self.ticket_counter}-{member.display_name}", auto_archive_duration=60)
self.ticket_counter += 1
self.data['ticket_counter'] = self.ticket_counter
self.save_config()

if self.data.get('log_channel_id'):
log_channel = self.bot.get_channel(self.data['log_channel_id'])
if log_channel:
embed = nextcord.Embed(title="Ticket Opened", color=nextcord.Color.green())
embed.set_thumbnail(url=member.avatar.url)
embed.add_field(name="Created By", value=f"{member.display_name}", inline=False)
embed.add_field(name="User ID", value=member.id, inline=False)
embed.add_field(name="Opened", value=interaction.created_at.strftime("%Y-%m-%d %H:%M:%S"), inline=False)
embed.add_field(name="Category", value=category, inline=False)
embed.add_field(name="Ticket Name", value=thread.name, inline=False)
view = View(timeout=None)
view.add_item(Button(label="Go to Ticket", style=nextcord.ButtonStyle.link, url=thread.jump_url))
await log_channel.send(embed=embed, view=view)

close_button = Button(label="Close Ticket", style=nextcord.ButtonStyle.red, custom_id=f"close_ticket_{thread.id}")
close_button.callback = self.button_callback
view = View(timeout=None)
view.add_item(close_button)
embed = nextcord.Embed(title="Your Ticket", description="Support will be with you shortly. Click the button to close this ticket.")
embed.add_field(name="Explain your issue", value="Provide details about your issue to help us assist you.", inline=False)
await thread.send(member.mention, embed=embed, view=view)
await interaction.response.send_message("Ticket created!", ephemeral=True)

async def close_ticket(self, interaction: nextcord.Interaction, thread: nextcord.Thread):
if not thread.archived:
await interaction.response.send_message(
embed=nextcord.Embed(title="Closed", description="Your ticket has been closed.", color=nextcord.Color.red()),
ephemeral=True
)
await thread.edit(archived=True, locked=True)

if self.transcript_enabled:
messages = await thread.history(limit=100).flatten()
transcript = StringIO()
for msg in reversed(messages):
transcript.write(f"{msg.author.display_name} [{msg.created_at}]: {msg.content}\n")

transcript.seek(0)

if self.dm_on_close:
try:
await interaction.user.send(file=nextcord.File(transcript, filename=f"{thread.name}_transcript.txt"))
except nextcord.Forbidden:
pass

transcript.seek(0)

if 'log_channel_id' in self.data:
log_channel = self.bot.get_channel(self.data['log_channel_id'])
if log_channel:
await log_channel.send(file=nextcord.File(transcript, filename=f"{thread.name}_transcript.txt"))

self.data['buttons'] = [button for button in self.data['buttons'] if button['message_id'] != thread.last_message_id]
self.save_config()

@tickets.error
@setup_ticket.error
@setup_log.error
async def tickets_error(self, ctx, error):
if isinstance(error, commands.MissingPermissions):
await ctx.send("You don't have permission to use this command.")

def setup(bot):
bot.add_cog(TicketSystem(bot))

0 comments on commit a2c10ff

Please sign in to comment.