mirror of
https://github.com/Cog-Creators/Red-DiscordBot.git
synced 2025-11-06 03:08:55 -05:00
* Add support for set api Modals Co-authored-by: TrustyJAID <TrustyJAID@gmail.com> * Blaacckkkk! * Swap locations of interaction and button. * Clarified template tokens * Update docs and some string * More docs * Rework the client Co-authored-by: TrustyJAID <TrustyJAID@gmail.com> * Goddamned black! * Missed a few arguments * Black... Again * Update redbot/core/utils/views.py Co-authored-by: TrustyJAID <TrustyJAID@gmail.com> * Update redbot/core/core_commands.py Co-authored-by: TrustyJAID <TrustyJAID@gmail.com> Co-authored-by: TrustyJAID <TrustyJAID@gmail.com>
177 lines
6.5 KiB
Python
177 lines
6.5 KiB
Python
from __future__ import annotations
|
|
|
|
import discord
|
|
|
|
from discord.ext.commands import BadArgument
|
|
from typing import List, Dict, Union, Optional
|
|
from redbot.core.commands.converter import get_dict_converter
|
|
from redbot.core.i18n import Translator
|
|
|
|
_ = Translator("UtilsViews", __file__)
|
|
|
|
|
|
class SetApiModal(discord.ui.Modal):
|
|
"""
|
|
A secure ``discord.ui.Modal`` used to set API keys.
|
|
|
|
This Modal can either be used standalone with its own ``discord.ui.View``
|
|
for custom implementations, or created via ``SetApiView``
|
|
to have an easy to implemement secure way of setting API keys.
|
|
|
|
Parameters
|
|
----------
|
|
default_service: Optional[str]
|
|
The service to add the API keys to.
|
|
If this is omitted the bot owner is allowed to set his own service.
|
|
Defaults to ``None``.
|
|
default_keys: Optional[Dict[str, str]]
|
|
The API keys the service is expecting.
|
|
This will only allow the bot owner to set keys the Modal is expecting.
|
|
Defaults to ``None``.
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
default_service: Optional[str] = None,
|
|
default_keys: Optional[Dict[str, str]] = None,
|
|
):
|
|
self.default_service = default_service
|
|
self.default_keys: List[str] = []
|
|
if default_keys is not None:
|
|
self.default_keys = list(default_keys.keys())
|
|
self.default_keys_fmt = self._format_keys(default_keys)
|
|
|
|
_placeholder_service = "service"
|
|
if self.default_service is not None:
|
|
_placeholder_service = self.default_service
|
|
_placeholder_token = "client_id YOUR_CLIENT_ID\nclient_secret YOUR_CLIENT_SECRET"
|
|
if self.default_keys_fmt is not None:
|
|
_placeholder_token = self.default_keys_fmt
|
|
|
|
self.title = _("Set API Keys")
|
|
self.keys_label = _("Keys and tokens")
|
|
if self.default_service is not None:
|
|
self.title = _("Set API Keys for {service}").format(service=self.default_service)
|
|
self.keys_label = _("Keys and tokens for {service}").format(
|
|
service=self.default_service
|
|
)
|
|
self.default_service = self.default_service.lower()
|
|
# Lower here to prevent someone from capitalizing a service name for the sake of UX.
|
|
|
|
super().__init__(title=self.title)
|
|
|
|
self.service_input = discord.ui.TextInput(
|
|
label=_("Service"),
|
|
required=True,
|
|
placeholder=_placeholder_service,
|
|
default=self.default_service,
|
|
)
|
|
|
|
self.token_input = discord.ui.TextInput(
|
|
label=self.keys_label,
|
|
style=discord.TextStyle.long,
|
|
required=True,
|
|
placeholder=_placeholder_token,
|
|
default=self.default_keys_fmt,
|
|
)
|
|
|
|
if self.default_service is None:
|
|
self.add_item(self.service_input)
|
|
self.add_item(self.token_input)
|
|
|
|
@staticmethod
|
|
def _format_keys(keys: Optional[Dict[str, str]]) -> Optional[str]:
|
|
"""Format the keys to be used on a long discord.TextInput format"""
|
|
if keys is not None:
|
|
ret = ""
|
|
for k, v in keys.items():
|
|
if v:
|
|
ret += f"{k} {v}\n"
|
|
else:
|
|
ret += f"{k} YOUR_{k.upper()}\n"
|
|
return ret
|
|
else:
|
|
return None
|
|
|
|
async def on_submit(self, interaction: discord.Interaction):
|
|
if not await interaction.client.is_owner(
|
|
interaction.user
|
|
): # Prevent non-bot owners from somehow aquiring and saving the modal.
|
|
return await interaction.response.send_message(
|
|
_("This modal is for bot owners only. Whoops!"), ephemeral=True
|
|
)
|
|
|
|
if self.default_keys is not None:
|
|
converter = get_dict_converter(*self.default_keys, delims=[";", ",", " "])
|
|
else:
|
|
converter = get_dict_converter(delims=[";", ",", " "])
|
|
tokens = " ".join(self.token_input.value.split("\n")).rstrip()
|
|
|
|
try:
|
|
tokens = await converter().convert(None, tokens)
|
|
except BadArgument as exc:
|
|
return await interaction.response.send_message(
|
|
_("{error_message}\nPlease try again.").format(error_message=str(exc)),
|
|
ephemeral=True,
|
|
)
|
|
|
|
if self.default_service is not None: # Check is there is a service set.
|
|
await interaction.client.set_shared_api_tokens(self.default_service, **tokens)
|
|
return await interaction.response.send_message(
|
|
_("`{service}` API tokens have been set.").format(service=self.default_service),
|
|
ephemeral=True,
|
|
)
|
|
else:
|
|
service = self.service_input.value.lower()
|
|
await interaction.client.set_shared_api_tokens(service, **tokens)
|
|
return await interaction.response.send_message(
|
|
_("`{service}` API tokens have been set.").format(service=service),
|
|
ephemeral=True,
|
|
)
|
|
|
|
|
|
class SetApiView(discord.ui.View):
|
|
"""
|
|
A secure ``discord.ui.View`` used to set API keys.
|
|
|
|
This view is an standalone, easy to implement ``discord.ui.View``
|
|
to allow an bot owner to securely set API keys in a public environment.
|
|
|
|
Parameters
|
|
----------
|
|
default_service: Optional[str]
|
|
The service to add the API keys to.
|
|
If this is omitted the bot owner is allowed to set his own service.
|
|
Defaults to ``None``.
|
|
default_keys: Optional[Dict[str, str]]
|
|
The API keys the service is expecting.
|
|
This will only allow the bot owner to set keys the Modal is expecting.
|
|
Defaults to ``None``.
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
default_service: Optional[str] = None,
|
|
default_keys: Optional[Dict[str, str]] = None,
|
|
):
|
|
self.default_service = default_service
|
|
self.default_keys = default_keys
|
|
super().__init__()
|
|
|
|
async def interaction_check(self, interaction: discord.Interaction) -> bool:
|
|
if not await interaction.client.is_owner(interaction.user):
|
|
await interaction.response.send_message(
|
|
_("This button is for bot owners only, oh well."), ephemeral=True
|
|
)
|
|
return False
|
|
return True
|
|
|
|
@discord.ui.button(
|
|
label=_("Set API token"),
|
|
style=discord.ButtonStyle.grey,
|
|
)
|
|
async def auth_button(self, interaction: discord.Interaction, button: discord.Button):
|
|
return await interaction.response.send_modal(
|
|
SetApiModal(self.default_service, self.default_keys)
|
|
)
|