You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
143 lines
5.8 KiB
143 lines
5.8 KiB
import discord
|
|
from discord import app_commands
|
|
|
|
import traceback
|
|
|
|
# The guild in which this slash command will be registered.
|
|
# It is recommended to have a test guild to separate from your "production" bot
|
|
TEST_GUILD = discord.Object(0)
|
|
# The ID of the channel where reports will be sent to
|
|
REPORTS_CHANNEL_ID = 0
|
|
|
|
|
|
class MyClient(discord.Client):
|
|
# Suppress error on the User attribute being None since it fills up later
|
|
user: discord.ClientUser
|
|
|
|
def __init__(self) -> None:
|
|
# Just default intents and a `discord.Client` instance
|
|
# We don't need a `commands.Bot` instance because we are not
|
|
# creating text-based commands.
|
|
intents = discord.Intents.default()
|
|
super().__init__(intents=intents)
|
|
|
|
# We need an `discord.app_commands.CommandTree` instance
|
|
# to register application commands (slash commands in this case)
|
|
self.tree = app_commands.CommandTree(self)
|
|
|
|
async def on_ready(self):
|
|
print(f'Logged in as {self.user} (ID: {self.user.id})')
|
|
print('------')
|
|
|
|
async def setup_hook(self) -> None:
|
|
await self.tree.sync(guild=TEST_GUILD)
|
|
|
|
|
|
# Define a modal dialog for reporting issues or feedback
|
|
class ReportModal(discord.ui.Modal, title='Your Report'):
|
|
topic = discord.ui.Label(
|
|
text='Topic',
|
|
description='Select the topic of the report.',
|
|
component=discord.ui.Select(
|
|
placeholder='Choose a topic...',
|
|
options=[
|
|
discord.SelectOption(label='Bug', description='Report a bug in the bot'),
|
|
discord.SelectOption(label='Feedback', description='Provide feedback or suggestions'),
|
|
discord.SelectOption(label='Feature Request', description='Request a new feature'),
|
|
discord.SelectOption(label='Performance', description='Report performance issues'),
|
|
discord.SelectOption(label='UI/UX', description='Report user interface or experience issues'),
|
|
discord.SelectOption(label='Security', description='Report security vulnerabilities'),
|
|
discord.SelectOption(label='Other', description='Other types of reports'),
|
|
],
|
|
),
|
|
)
|
|
report_title = discord.ui.Label(
|
|
text='Title',
|
|
description='A short title for the report.',
|
|
component=discord.ui.TextInput(
|
|
style=discord.TextStyle.short,
|
|
placeholder='The bot does not respond to commands',
|
|
max_length=120,
|
|
),
|
|
)
|
|
description = discord.ui.Label(
|
|
text='Description',
|
|
description='A detailed description of the report.',
|
|
component=discord.ui.TextInput(
|
|
style=discord.TextStyle.paragraph,
|
|
placeholder='When I use /ping, the bot does not respond at all. There are no error messages.',
|
|
max_length=2000,
|
|
),
|
|
)
|
|
images = discord.ui.Label(
|
|
text='Images',
|
|
description='Upload any relevant images for your report (optional).',
|
|
component=discord.ui.FileUpload(
|
|
max_values=10,
|
|
custom_id='report_images',
|
|
required=False,
|
|
),
|
|
)
|
|
footer = discord.ui.TextDisplay(
|
|
'Please ensure your report follows the server rules. Any kind of abuse will result in a ban.'
|
|
)
|
|
|
|
def to_view(self, interaction: discord.Interaction) -> discord.ui.LayoutView:
|
|
# Tell the type checker what our components are...
|
|
assert isinstance(self.topic.component, discord.ui.Select)
|
|
assert isinstance(self.description.component, discord.ui.TextInput)
|
|
assert isinstance(self.report_title.component, discord.ui.TextInput)
|
|
assert isinstance(self.images.component, discord.ui.FileUpload)
|
|
|
|
topic = self.topic.component.values[0]
|
|
title = self.report_title.component.value
|
|
description = self.description.component.value
|
|
files = self.images.component.values
|
|
|
|
view = discord.ui.LayoutView()
|
|
container = discord.ui.Container()
|
|
view.add_item(container)
|
|
|
|
container.add_item(discord.ui.TextDisplay(f'-# User Report\n## {topic}'))
|
|
|
|
timestamp = discord.utils.format_dt(interaction.created_at, 'F')
|
|
footer = discord.ui.TextDisplay(f'-# Reported by {interaction.user} (ID: {interaction.user.id}) | {timestamp}')
|
|
|
|
container.add_item(discord.ui.TextDisplay(f'### {title}'))
|
|
container.add_item(discord.ui.TextDisplay(f'>>> {description}'))
|
|
|
|
if files:
|
|
gallery = discord.ui.MediaGallery()
|
|
gallery.items = [discord.MediaGalleryItem(media=attachment.url) for attachment in files]
|
|
container.add_item(gallery)
|
|
|
|
container.add_item(footer)
|
|
return view
|
|
|
|
async def on_submit(self, interaction: discord.Interaction[MyClient]):
|
|
view = self.to_view(interaction)
|
|
|
|
# Send the report to the designated channel
|
|
reports_channel = interaction.client.get_partial_messageable(REPORTS_CHANNEL_ID)
|
|
await reports_channel.send(view=view)
|
|
await interaction.response.send_message('Thank you for your report! We will look into it shortly.', ephemeral=True)
|
|
|
|
async def on_error(self, interaction: discord.Interaction, error: Exception) -> None:
|
|
await interaction.response.send_message('Oops! Something went wrong.', ephemeral=True)
|
|
|
|
# Make sure we know what the error actually is
|
|
traceback.print_exception(type(error), error, error.__traceback__)
|
|
|
|
|
|
client = MyClient()
|
|
|
|
|
|
@client.tree.command(guild=TEST_GUILD, description='Report an issue or provide feedback.')
|
|
async def report(interaction: discord.Interaction):
|
|
# Send the modal with an instance of our `ReportModal` class
|
|
# Since modals require an interaction, they cannot be done as a response to a text command.
|
|
# They can only be done as a response to either an application command or a button press.
|
|
await interaction.response.send_modal(ReportModal())
|
|
|
|
|
|
client.run('token')
|
|
|