GalaxyCogs/issues/modals.py

384 lines
15 KiB
Python

import aiohttp
import discord
from redbot.core import Config
# pylint: disable=arguments-differ
#
# Misc. functions
#
def construct_embed(interaction: discord.Interaction, fields: list[discord.Embed.fields], color: str):
embed = discord.Embed(title="Issue Request", color=color)
for item in fields:
title = item.label
value = item.value
if value is not None:
if len(value) > 1024:
words = value.split()
split_value = []
current_part = ""
for word in words:
if len(current_part) + len(word) + 1 <= 1024:
current_part += word + " "
else:
split_value.append(current_part.strip())
current_part = word + " "
if current_part:
split_value.append(current_part.strip())
for i, part in enumerate(split_value):
embed.add_field(
name=title if i == 0 else "\u200b", value=part, inline=False
)
else:
embed.add_field(name=title, value=value, inline=False)
if interaction.user.discriminator == "0":
username = interaction.user.name
else:
username = f"{interaction.user.name}#{interaction.user.discriminator}"
embed.set_footer(
text=f"Submitted by {username} ({interaction.user.id})",
icon_url=interaction.user.display_avatar.url,
)
return embed
#
# Modals for the core '/issues' command.
#
class BotBugModal(discord.ui.Modal, title="Creating issue..."):
def __init__(self, color, cog_instance, original_interaction):
super().__init__()
self.color = color
self.cog_instance = cog_instance
self.original_interaction = original_interaction
bug_description = discord.ui.TextInput(
label="Describe the bug",
placeholder="A clear and concise description of what the bug is.",
style=discord.TextStyle.paragraph,
required=True,
max_length=2048
)
reproduction_steps = discord.ui.TextInput(
label="To Reproduce",
placeholder="What caused the bug?",
style=discord.TextStyle.paragraph,
required=True,
max_length=2048
)
expected_behavior = discord.ui.TextInput(
label="Expected Behavior",
placeholder="A clear and concise description of what you expected to happen.",
style=discord.TextStyle.paragraph,
required=True,
max_length=2048
)
additional_context = discord.ui.TextInput(
label="Additional Context",
placeholder="Add any other context about the problem here.",
style=discord.TextStyle.paragraph,
required=False,
max_length=2048
)
async def on_submit(self, interaction: discord.Interaction):
fields = [self.bug_description, self.reproduction_steps, self.expected_behavior, self.additional_context]
embed = construct_embed(interaction, fields, self.color)
embed.set_author(name="Bot Bug Report")
await self.cog_instance.submit_issue_request(interaction=interaction, original_interaction=self.original_interaction, embed=embed)
class CogBugModal(discord.ui.Modal, title="Creating issue..."):
def __init__(self, color, cog_instance, original_interaction):
super().__init__()
self.color = color
self.cog_instance = cog_instance
self.original_interaction = original_interaction
cog_name = discord.ui.TextInput(
label="What cog is causing this error?",
placeholder="If unsure, put \"GalaxyCogs\".",
style=discord.TextStyle.short,
required=True,
max_length=50
)
bug_description = discord.ui.TextInput(
label="Describe the bug",
placeholder="A clear and concise description of what the bug is.",
style=discord.TextStyle.paragraph,
required=True,
max_length=2048
)
reproduction_steps = discord.ui.TextInput(
label="To Reproduce",
placeholder="What caused the bug?",
style=discord.TextStyle.paragraph,
required=True,
max_length=2048
)
expected_behavior = discord.ui.TextInput(
label="Expected Behavior",
placeholder="A clear and concise description of what you expected to happen.",
style=discord.TextStyle.paragraph,
required=True,
max_length=2048
)
additional_context = discord.ui.TextInput(
label="Additional Context",
placeholder="Add any other context about the problem here.",
style=discord.TextStyle.paragraph,
required=False,
max_length=2048
)
async def on_submit(self, interaction: discord.Interaction):
fields = [self.cog_name, self.bug_description, self.reproduction_steps, self.expected_behavior, self.additional_context]
embed = construct_embed(interaction, fields, self.color)
embed.set_author(name="Cog Bug Report")
await self.cog_instance.submit_issue_request(interaction=interaction, original_interaction=self.original_interaction, embed=embed)
class BotSuggestionModal(discord.ui.Modal, title="Creating issue..."):
def __init__(self, color, cog_instance, original_interaction):
super().__init__()
self.color = color
self.cog_instance = cog_instance
self.original_interaction = original_interaction
suggestion_description = discord.ui.TextInput(
label="Describe your suggestion.",
placeholder="A clear and concise description of what your suggestion is.",
style=discord.TextStyle.paragraph,
required=True,
max_length=2048
)
alternatives = discord.ui.TextInput(
label="Describe alternatives you've considered.",
placeholder="A clear and concise description of any alternative solutions or features you've cnosidered.",
style=discord.TextStyle.paragraph,
required=True,
max_length=2048
)
additional_context = discord.ui.TextInput(
label="Additional Context",
placeholder="Add any other context about your suggestion here.",
style=discord.TextStyle.paragraph,
required=False,
max_length=2048
)
async def on_submit(self, interaction: discord.Interaction):
fields = [self.suggestion_description, self.alternatives, self.additional_context]
embed = construct_embed(interaction, fields, self.color)
embed.set_author(name="Cog Suggestion")
await self.cog_instance.submit_issue_request(interaction=interaction, original_interaction=self.original_interaction, embed=embed)
class CogSuggestionModal(discord.ui.Modal, title="Creating issue..."):
def __init__(self, color, cog_instance, original_interaction):
super().__init__()
self.color = color
self.cog_instance = cog_instance
self.original_interaction = original_interaction
cog_name = discord.ui.TextInput(
label="What cog is your suggestion for?",
placeholder="If unsure, put \"GalaxyCogs\".",
style=discord.TextStyle.short,
required=True,
max_length=50
)
suggestion_description = discord.ui.TextInput(
label="Describe your suggestion.",
placeholder="A clear and concise description of what your suggestion is.",
style=discord.TextStyle.paragraph,
required=True,
max_length=2048
)
alternatives = discord.ui.TextInput(
label="Describe alternatives you've considered.",
placeholder="A clear and concise description of any alternative solutions or features you've cnosidered.",
style=discord.TextStyle.paragraph,
required=True,
max_length=2048
)
additional_context = discord.ui.TextInput(
label="Additional Context",
placeholder="Add any other context about your suggestion here.",
style=discord.TextStyle.paragraph,
required=False,
max_length=2048
)
async def on_submit(self, interaction: discord.Interaction):
fields = [self.cog_name, self.suggestion_description, self.alternatives, self.additional_context]
embed = construct_embed(interaction, fields, self.color)
embed.set_author(name="Cog Suggestion")
await self.cog_instance.submit_issue_request(interaction=interaction, original_interaction=self.original_interaction, embed=embed)
#
# Response modal
#
class IssueResponseModal(discord.ui.Modal, title="Sending response message..."):
def __init__(self, channel, message_id, user, approved):
super().__init__()
self.channel = channel
self.message_id = message_id
self.user = user
self.approved = approved
self.config = Config.get_conf(None, cog_name="Issues", identifier=4285273314713)
issue_title_input = discord.ui.TextInput(
label="Title",
placeholder="Only use this if you're accepting the issue request.",
style=discord.TextStyle.short,
required=False,
max_length=200,
)
response = discord.ui.TextInput(
label="Response",
placeholder="",
style=discord.TextStyle.paragraph,
required=False,
max_length=1024,
)
async def on_submit(self, interaction: discord.Interaction):
message: discord.Message = await self.channel.fetch_message(self.message_id)
embed = message.embeds[0]
field_values = []
field_names = []
if self.approved:
embed.color = 1226519
embed.title = "Issue Request Approved"
status = "accepted"
else:
embed.color = 15671552
embed.title = "Issue Request Denied"
status = "denied"
await interaction.response.send_message(content=f"Issue request {status}.", ephemeral=True)
if self.response.value != "":
embed.add_field(
name=f"Response from {interaction.user.name}",
value=self.response.value,
inline=False,
)
if self.approved:
for field in embed.fields:
field_names.append(f"**{field.name}**")
field_values.append(field.value)
if self.issue_title_input.value != "":
_issue_title = self.issue_title_input.value
else:
_issue_title = "Automatically generated issue"
if embed.author.name == "Bot Bug Report":
issue_title = f"[BOT BUG] {_issue_title}"
desired_labels = ["bot", "bug"]
elif embed.author.name == "Bot Suggestion":
issue_title = f"[BOT SUGGESTION] {_issue_title}"
desired_labels = ["bot", "enhancement"]
elif embed.author.name == "Cog Bug Report":
issue_title = f"[{field_values[0]}] {_issue_title}"
desired_labels = ["cog", "bug"]
elif embed.author.name == "Cog Suggestion":
issue_title = f"[{field_values[0]}] {_issue_title}"
desired_labels = ["cog", "enhancement"]
headers = {
"Authorization": f"Bearer {await self.config.gitea_token()}",
"Accept": "application/json",
}
url = f"{await self.config.gitea_root_url()}/api/v1/repos/{await self.config.gitea_repository_owner()}/{await self.config.gitea_repository()}/issues"
issue_body = "\n".join(
[f"{name}\n{value}" for name, value in zip(field_names, field_values)]
)
# async def fetch_labels():
# async with aiohttp.ClientSession(headers=headers) as session:
# async with session.post(url=f"{await self.config.gitea_root_url()}/api/v1/repos/{await self.config.gitea_repository_owner()}/{await self.config.gitea_repository()}/labels") as response:
# label_list = []
# for label in response.json():
# if label["name"] in desired_labels:
# label_list.append(label["id"])
# if label_list is None:
# print("Error! Labels are not properly configured on the target repository.")
# return await label_list
issue_labels = None
if issue_labels is None:
issue_data = {"title": issue_title, "body": issue_body}
else:
issue_data = {"title": issue_title, "body": issue_body, "labels": issue_labels}
async def create_issue():
async with aiohttp.ClientSession(headers=headers) as session:
async with session.post(url, json=issue_data) as response:
return await response.json(), response.status
response_json, status_code = await create_issue()
if status_code == 201:
await interaction.response.send_message(
content=f"Issue request {status}.\n[Issue successfully created.]({response_json.get('html_url')})",
ephemeral=True,
)
embed.url = response_json.get("html_url")
await message.edit(embed=embed, view=None)
await self.user.send(embed=embed)
#
# Configuration modal
#
class IssuesConfigurationModal(discord.ui.Modal, title="Modifying configuration..."):
def __init__(self, config, ctx):
super().__init__()
self.config = config
self.ctx = ctx
gitea_root_url = discord.ui.TextInput(
label="Gitea Root URL",
placeholder="https://try.gitea.io",
style=discord.TextStyle.short,
required=False,
max_length=200
)
gitea_repository_owner = discord.ui.TextInput(
label="Gitea Repository Owner",
placeholder="foo",
style=discord.TextStyle.short,
required=False,
max_length=200
)
gitea_repository = discord.ui.TextInput(
label="Gitea Repository Name",
placeholder="bar",
style=discord.TextStyle.short,
required=False,
max_length=200
)
gitea_token = discord.ui.TextInput(
label="Gitea User Access Token",
placeholder="Generate one from your user settings page.",
style=discord.TextStyle.short,
required=False,
max_length=200
)
async def on_submit(self, interaction: discord.Interaction):
if self.gitea_token.value != "":
await self.config.gitea_token.set(self.gitea_token.value)
if self.gitea_root_url.value != "":
await self.config.gitea_root_url.set(self.gitea_root_url.value)
if self.gitea_repository_owner.value != "":
await self.config.gitea_repository_owner.set(self.gitea_repository_owner.value)
if self.gitea_repository.value != "":
await self.config.gitea_repository.set(self.gitea_repository.value)
await interaction.response.send_message(content="Configuration changed!")