mirror of
https://github.com/wlinator/luminara.git
synced 2024-10-02 18:23:12 +00:00
Refactor: Code cleanup and consistency
This commit is contained in:
parent
6d85960fca
commit
67c423fc7e
59 changed files with 914 additions and 389 deletions
10
.env.example
10
.env.example
|
@ -1,15 +1,15 @@
|
|||
TOKEN=
|
||||
INSTANCE=BETA
|
||||
INSTANCE=
|
||||
OWNER_IDS=
|
||||
|
||||
XP_GAIN_PER_MESSAGE=1
|
||||
XP_GAIN_COOLDOWN=8
|
||||
XP_GAIN_PER_MESSAGE=
|
||||
XP_GAIN_COOLDOWN=
|
||||
|
||||
DBX_OAUTH2_REFRESH_TOKEN=
|
||||
DBX_APP_KEY=
|
||||
DBX_APP_SECRET=
|
||||
|
||||
MARIADB_USER=wlinator
|
||||
MARIADB_USER=
|
||||
MARIADB_PASSWORD=
|
||||
MARIADB_ROOT_PASSWORD=
|
||||
MARIADB_DATABASE=lumidb
|
||||
MARIADB_DATABASE=
|
||||
|
|
33
.pre-commit-config.yaml
Normal file
33
.pre-commit-config.yaml
Normal file
|
@ -0,0 +1,33 @@
|
|||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.6.0
|
||||
hooks:
|
||||
- id: check-yaml
|
||||
- id: check-json
|
||||
- id: check-toml
|
||||
|
||||
- repo: https://github.com/asottile/add-trailing-comma
|
||||
rev: v3.1.0
|
||||
hooks:
|
||||
- id: add-trailing-comma
|
||||
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.5.2
|
||||
hooks:
|
||||
# Run the linter.
|
||||
- id: ruff
|
||||
args: [--fix]
|
||||
# Run the formatter.
|
||||
- id: ruff-format
|
||||
|
||||
- repo: https://github.com/gitleaks/gitleaks
|
||||
rev: v8.18.4
|
||||
hooks:
|
||||
- id: gitleaks
|
||||
|
||||
- repo: https://github.com/hija/clean-dotenv
|
||||
rev: v0.0.7
|
||||
hooks:
|
||||
- id: clean-dotenv
|
||||
|
||||
exclude: ".archive/"
|
18
Client.py
18
Client.py
|
@ -46,7 +46,8 @@ class LumiBot(bridge.Bot):
|
|||
|
||||
@staticmethod
|
||||
async def convert_to_user(
|
||||
ctx: commands.Context | bridge.Context, user_id: int
|
||||
ctx: commands.Context | bridge.Context,
|
||||
user_id: int,
|
||||
) -> Optional[discord.User]:
|
||||
"""
|
||||
Converts a user ID to a User object.
|
||||
|
@ -73,7 +74,8 @@ class LumiBot(bridge.Bot):
|
|||
|
||||
@staticmethod
|
||||
async def convert_to_emoji(
|
||||
ctx: commands.Context | bridge.Context, emoji: str
|
||||
ctx: commands.Context | bridge.Context,
|
||||
emoji: str,
|
||||
) -> Optional[discord.Emoji]:
|
||||
"""
|
||||
Converts a emoji to an Emoji object.
|
||||
|
@ -98,7 +100,8 @@ class LumiBot(bridge.Bot):
|
|||
|
||||
@staticmethod
|
||||
async def convert_to_text_channel(
|
||||
ctx: commands.Context | bridge.Context, channel_id: int
|
||||
ctx: commands.Context | bridge.Context,
|
||||
channel_id: int,
|
||||
) -> Optional[discord.TextChannel]:
|
||||
"""
|
||||
Converts a channel ID to a TextChannel object.
|
||||
|
@ -127,7 +130,8 @@ class LumiBot(bridge.Bot):
|
|||
|
||||
@staticmethod
|
||||
async def convert_to_member(
|
||||
ctx: commands.Context, user_id: int
|
||||
ctx: commands.Context,
|
||||
user_id: int,
|
||||
) -> Optional[discord.Member]:
|
||||
"""
|
||||
Converts a user ID to a Member object.
|
||||
|
@ -155,7 +159,8 @@ class LumiBot(bridge.Bot):
|
|||
|
||||
@staticmethod
|
||||
async def get_or_fetch_channel(
|
||||
guild: discord.Guild, channel_id: int
|
||||
guild: discord.Guild,
|
||||
channel_id: int,
|
||||
) -> Optional[discord.abc.GuildChannel]:
|
||||
"""
|
||||
Retrieves a channel from the guild's cache or fetches it from the API if not found.
|
||||
|
@ -179,7 +184,8 @@ class LumiBot(bridge.Bot):
|
|||
|
||||
@staticmethod
|
||||
async def get_or_fetch_member(
|
||||
guild: discord.Guild, user_id: int
|
||||
guild: discord.Guild,
|
||||
user_id: int,
|
||||
) -> Optional[discord.Member]:
|
||||
"""
|
||||
Retrieves a member from the guild's cache or fetches them from the API if not found.
|
||||
|
|
|
@ -34,7 +34,8 @@ async def on_command_error(ctx, error):
|
|||
elif isinstance(error, commands.CommandOnCooldown):
|
||||
author_text = CONST.STRINGS["error_command_cooldown_author"]
|
||||
description = CONST.STRINGS["error_command_cooldown_description"].format(
|
||||
int(error.retry_after // 60), int(error.retry_after % 60)
|
||||
int(error.retry_after // 60),
|
||||
int(error.retry_after % 60),
|
||||
)
|
||||
ephemeral = True
|
||||
|
||||
|
@ -62,13 +63,13 @@ async def on_command_error(ctx, error):
|
|||
elif isinstance(error, LumiExceptions.LumiException):
|
||||
author_text = CONST.STRINGS["error_lumi_exception_author"]
|
||||
description = CONST.STRINGS["error_lumi_exception_description"].format(
|
||||
str(error)
|
||||
str(error),
|
||||
)
|
||||
|
||||
elif isinstance(error, LumiExceptions.NotAllowedInChannel):
|
||||
author_text = CONST.STRINGS["error_not_allowed_in_channel_author"]
|
||||
description = CONST.STRINGS["error_not_allowed_in_channel_description"].format(
|
||||
error.command_channel.mention
|
||||
error.command_channel.mention,
|
||||
)
|
||||
ephemeral = True
|
||||
|
||||
|
@ -89,7 +90,7 @@ async def on_command_error(ctx, error):
|
|||
|
||||
async def on_error(event: str, *args, **kwargs) -> None:
|
||||
logger.exception(
|
||||
f"on_error INFO: errors.event.{event} | '*args': {args} | '**kwargs': {kwargs}"
|
||||
f"on_error INFO: errors.event.{event} | '*args': {args} | '**kwargs': {kwargs}",
|
||||
)
|
||||
logger.exception(f"on_error EXCEPTION: {sys.exc_info()}")
|
||||
traceback.print_exc()
|
||||
|
|
|
@ -25,9 +25,14 @@ class EventHandler(Cog):
|
|||
embed = Greet.message(member, config.welcome_message)
|
||||
|
||||
try:
|
||||
await member.guild.get_channel(config.welcome_channel_id).send(embed=embed, content=member.mention)
|
||||
await member.guild.get_channel(config.welcome_channel_id).send(
|
||||
embed=embed,
|
||||
content=member.mention,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.warning(f"Greet message not sent in '{member.guild.name}'. Channel ID may be invalid. {e}")
|
||||
logger.warning(
|
||||
f"Greet message not sent in '{member.guild.name}'. Channel ID may be invalid. {e}",
|
||||
)
|
||||
|
||||
@Cog.listener()
|
||||
async def on_member_update(self, before, after):
|
||||
|
@ -44,16 +49,25 @@ class EventHandler(Cog):
|
|||
if not config.boost_channel_id:
|
||||
return
|
||||
|
||||
embed = lib.embeds.boost.Boost.message(member, config.boost_message, config.boost_image_url)
|
||||
embed = lib.embeds.boost.Boost.message(
|
||||
member,
|
||||
config.boost_message,
|
||||
config.boost_image_url,
|
||||
)
|
||||
|
||||
try:
|
||||
await member.guild.get_channel(config.boost_channel_id).send(embed=embed, content=member.mention)
|
||||
await member.guild.get_channel(config.boost_channel_id).send(
|
||||
embed=embed,
|
||||
content=member.mention,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.warning(f"Boost message not sent in '{member.guild.name}'. Channel ID may be invalid. {e}")
|
||||
logger.warning(
|
||||
f"Boost message not sent in '{member.guild.name}'. Channel ID may be invalid. {e}",
|
||||
)
|
||||
|
||||
@Cog.listener()
|
||||
async def on_command_completion(self, ctx) -> None:
|
||||
log_msg = '%s executed .%s' % (ctx.author.name, ctx.command.qualified_name)
|
||||
log_msg = "%s executed .%s" % (ctx.author.name, ctx.command.qualified_name)
|
||||
|
||||
if ctx.guild is not None:
|
||||
logger.debug(f"{log_msg} | guild: {ctx.guild.name} ")
|
||||
|
@ -62,7 +76,7 @@ class EventHandler(Cog):
|
|||
|
||||
@Cog.listener()
|
||||
async def on_application_command_completion(self, ctx) -> None:
|
||||
log_msg = '%s executed /%s' % (ctx.author.name, ctx.command.qualified_name)
|
||||
log_msg = "%s executed /%s" % (ctx.author.name, ctx.command.qualified_name)
|
||||
|
||||
if ctx.guild is not None:
|
||||
logger.debug(f"{log_msg} | guild: {ctx.guild.name} ")
|
||||
|
|
|
@ -38,9 +38,9 @@ class ReactionHandler:
|
|||
|
||||
if processed:
|
||||
await self.reaction_service.increment_reaction_usage(
|
||||
int(data["id"])
|
||||
int(data["id"]),
|
||||
)
|
||||
|
||||
|
||||
async def try_respond(self, data) -> bool:
|
||||
"""
|
||||
Tries to respond to the message.
|
||||
|
@ -53,7 +53,7 @@ class ReactionHandler:
|
|||
except Exception:
|
||||
pass
|
||||
return False
|
||||
|
||||
|
||||
async def try_react(self, data) -> bool:
|
||||
"""
|
||||
Tries to react to the message.
|
||||
|
@ -82,7 +82,7 @@ class ReactionListener(Cog):
|
|||
:param message: The message to process.
|
||||
"""
|
||||
if not message.author.bot and not BlacklistUserService.is_user_blacklisted(
|
||||
message.author.id
|
||||
message.author.id,
|
||||
):
|
||||
await ReactionHandler(self.client, message).run_checks()
|
||||
|
||||
|
|
|
@ -32,7 +32,8 @@ class XPHandler:
|
|||
self.author: discord.Member | discord.User = message.author
|
||||
self.guild: discord.Guild | None = message.guild
|
||||
self.xp_conf: XpService = XpService(
|
||||
self.author.id, self.guild.id if self.guild else 0
|
||||
self.author.id,
|
||||
self.guild.id if self.guild else 0,
|
||||
)
|
||||
self.guild_conf: Optional[GuildConfig] = None
|
||||
|
||||
|
@ -80,7 +81,8 @@ class XPHandler:
|
|||
|
||||
if level_message:
|
||||
level_channel: Optional[discord.TextChannel] = await self.get_level_channel(
|
||||
self.message, _gd
|
||||
self.message,
|
||||
_gd,
|
||||
)
|
||||
|
||||
if level_channel:
|
||||
|
@ -103,7 +105,9 @@ class XPHandler:
|
|||
|
||||
if role := self.guild.get_role(role_id):
|
||||
with contextlib.suppress(
|
||||
discord.Forbidden, discord.NotFound, discord.HTTPException
|
||||
discord.Forbidden,
|
||||
discord.NotFound,
|
||||
discord.HTTPException,
|
||||
):
|
||||
if isinstance(self.author, discord.Member):
|
||||
await self.author.add_roles(role, reason=reason)
|
||||
|
@ -112,12 +116,16 @@ class XPHandler:
|
|||
if replace and isinstance(self.author, discord.Member):
|
||||
if role := self.guild.get_role(previous or role_id):
|
||||
with contextlib.suppress(
|
||||
discord.Forbidden, discord.NotFound, discord.HTTPException
|
||||
discord.Forbidden,
|
||||
discord.NotFound,
|
||||
discord.HTTPException,
|
||||
):
|
||||
await self.author.remove_roles(role, reason=reason)
|
||||
|
||||
async def get_level_channel(
|
||||
self, message: discord.Message, guild_config: GuildConfig
|
||||
self,
|
||||
message: discord.Message,
|
||||
guild_config: GuildConfig,
|
||||
) -> Optional[discord.TextChannel]:
|
||||
"""
|
||||
Retrieves the level up notification channel for the guild.
|
||||
|
@ -134,13 +142,16 @@ class XPHandler:
|
|||
|
||||
with contextlib.suppress(discord.HTTPException):
|
||||
return await self.client.convert_to_text_channel(
|
||||
context, guild_config.level_channel_id
|
||||
context,
|
||||
guild_config.level_channel_id,
|
||||
)
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
async def get_level_message(
|
||||
guild_config: GuildConfig, level_config: XpService, author: discord.Member
|
||||
guild_config: GuildConfig,
|
||||
level_config: XpService,
|
||||
author: discord.Member,
|
||||
) -> Optional[str]:
|
||||
"""
|
||||
Retrieves the level up message for the user.
|
||||
|
@ -161,11 +172,14 @@ class XPHandler:
|
|||
case 2:
|
||||
if not guild_config.level_message:
|
||||
level_message = XPHandler.level_message_generic(
|
||||
level_config.level, author
|
||||
level_config.level,
|
||||
author,
|
||||
)
|
||||
else:
|
||||
level_message = formatter.template(
|
||||
guild_config.level_message, author.name, level_config.level
|
||||
guild_config.level_message,
|
||||
author.name,
|
||||
level_config.level,
|
||||
)
|
||||
case _:
|
||||
raise ValueError("Invalid level message type")
|
||||
|
|
|
@ -29,7 +29,8 @@ def allowed_in_channel():
|
|||
|
||||
if command_channel_id:
|
||||
command_channel = await ctx.bot.get_or_fetch_channel(
|
||||
ctx.guild, command_channel_id
|
||||
ctx.guild,
|
||||
command_channel_id,
|
||||
)
|
||||
|
||||
if ctx.channel.id != command_channel_id and command_channel:
|
||||
|
|
|
@ -6,7 +6,8 @@ from lib import formatter
|
|||
|
||||
def clean_error_embed(ctx):
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.red(), description=f"**{ctx.author.name}** "
|
||||
color=discord.Color.red(),
|
||||
description=f"**{ctx.author.name}** ",
|
||||
)
|
||||
|
||||
return embed
|
||||
|
@ -73,7 +74,8 @@ class GenericErrors:
|
|||
else:
|
||||
embed.description += f"you can only do that command in {channel.mention}."
|
||||
embed.set_footer(
|
||||
text="This message will delete itself after 5s", icon_url=CONST.EXCLAIM_ICON
|
||||
text="This message will delete itself after 5s",
|
||||
icon_url=CONST.EXCLAIM_ICON,
|
||||
)
|
||||
|
||||
return embed
|
||||
|
@ -103,7 +105,8 @@ class EconErrors:
|
|||
f"you already have a game of {ctx.command.name} running."
|
||||
)
|
||||
embed.set_footer(
|
||||
text="Please finish this game first", icon_url=CONST.EXCLAIM_ICON
|
||||
text="Please finish this game first",
|
||||
icon_url=CONST.EXCLAIM_ICON,
|
||||
)
|
||||
|
||||
return embed
|
||||
|
@ -134,7 +137,8 @@ class HelpErrors:
|
|||
embed = clean_error_embed(ctx)
|
||||
embed.description += error
|
||||
embed.set_footer(
|
||||
text=f"See '{formatter.get_prefix(ctx)}help'", icon_url=CONST.EXCLAIM_ICON
|
||||
text=f"See '{formatter.get_prefix(ctx)}help'",
|
||||
icon_url=CONST.EXCLAIM_ICON,
|
||||
)
|
||||
|
||||
return embed
|
||||
|
|
|
@ -12,7 +12,8 @@ streak_icon = resources["icons"]["streak"]
|
|||
|
||||
def clean_info_embed(ctx):
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.blurple(), description=f"**{ctx.author.name}** "
|
||||
color=discord.Color.blurple(),
|
||||
description=f"**{ctx.author.name}** ",
|
||||
)
|
||||
|
||||
return embed
|
||||
|
@ -24,7 +25,8 @@ class MiscInfo:
|
|||
embed = clean_info_embed(ctx)
|
||||
embed.description += "I'm online!"
|
||||
embed.set_footer(
|
||||
text=f"Latency: {round(1000 * client.latency)}ms", icon_url=exclaim_icon
|
||||
text=f"Latency: {round(1000 * client.latency)}ms",
|
||||
icon_url=exclaim_icon,
|
||||
)
|
||||
|
||||
return embed
|
||||
|
@ -34,7 +36,8 @@ class MiscInfo:
|
|||
embed = clean_info_embed(ctx)
|
||||
embed.description += f"I've been online since <t:{unix_time}:R>"
|
||||
embed.set_footer(
|
||||
text=f"Latency: {round(1000 * client.latency)}ms", icon_url=exclaim_icon
|
||||
text=f"Latency: {round(1000 * client.latency)}ms",
|
||||
icon_url=exclaim_icon,
|
||||
)
|
||||
|
||||
return embed
|
||||
|
|
|
@ -11,10 +11,16 @@ cross_icon = resources["icons"]["cross"]
|
|||
exclaim_icon = resources["icons"]["exclaim"]
|
||||
logo = resources["logo"]["transparent"]
|
||||
|
||||
def create_embed(title: str, description: str, color: int, icon_url: str) -> discord.Embed:
|
||||
|
||||
def create_embed(
|
||||
title: str,
|
||||
description: str,
|
||||
color: int,
|
||||
icon_url: str,
|
||||
) -> discord.Embed:
|
||||
embed = discord.Embed(
|
||||
color=color,
|
||||
description=description
|
||||
description=description,
|
||||
)
|
||||
embed.set_author(name=title, icon_url=icon_url)
|
||||
embed.set_footer(text="Reaction Service", icon_url=logo)
|
||||
|
@ -22,24 +28,36 @@ def create_embed(title: str, description: str, color: int, icon_url: str) -> dis
|
|||
return embed
|
||||
|
||||
|
||||
def create_creation_embed(trigger_text: str, response: Optional[str], emoji_id: Optional[int], is_emoji: bool, is_full_match: bool) -> discord.Embed:
|
||||
def create_creation_embed(
|
||||
trigger_text: str,
|
||||
response: Optional[str],
|
||||
emoji_id: Optional[int],
|
||||
is_emoji: bool,
|
||||
is_full_match: bool,
|
||||
) -> discord.Embed:
|
||||
trigger_text = formatter.shorten(trigger_text, 50)
|
||||
if response:
|
||||
response = formatter.shorten(response, 50)
|
||||
|
||||
|
||||
description = (
|
||||
f"**Trigger Text:** `{trigger_text}`\n"
|
||||
f"**Reaction Type:** {'Emoji' if is_emoji else 'Text'}\n"
|
||||
f"{f'**Emoji ID:** `{str(emoji_id)}`' if is_emoji else f'**Response:** `{response}`'}\n"
|
||||
f"**Full Match:** `{is_full_match}`"
|
||||
f"**Full Match:** `{is_full_match}`"
|
||||
)
|
||||
return create_embed("Custom Reaction Created", description, 0xFF8C00, check_icon)
|
||||
|
||||
def create_failure_embed(trigger_text: str, is_emoji: bool, limit_reached: bool = False, trigger_already_exists: bool = False) -> discord.Embed:
|
||||
|
||||
def create_failure_embed(
|
||||
trigger_text: str,
|
||||
is_emoji: bool,
|
||||
limit_reached: bool = False,
|
||||
trigger_already_exists: bool = False,
|
||||
) -> discord.Embed:
|
||||
trigger_text = formatter.shorten(trigger_text, 50)
|
||||
|
||||
|
||||
description = f"**Trigger Text:** `{trigger_text}`\n"
|
||||
|
||||
|
||||
if limit_reached:
|
||||
description += "Failed to add custom reaction. You have reached the limit of 100 custom reactions for this server."
|
||||
elif trigger_already_exists:
|
||||
|
@ -47,23 +65,30 @@ def create_failure_embed(trigger_text: str, is_emoji: bool, limit_reached: bool
|
|||
else:
|
||||
description += "Failed to add custom reaction."
|
||||
|
||||
return create_embed("Custom Reaction Creation Failed", description, 0xFF4500, cross_icon)
|
||||
return create_embed(
|
||||
"Custom Reaction Creation Failed",
|
||||
description,
|
||||
0xFF4500,
|
||||
cross_icon,
|
||||
)
|
||||
|
||||
|
||||
def create_deletion_embed(trigger_text: str, is_emoji: bool) -> discord.Embed:
|
||||
trigger_text = formatter.shorten(trigger_text, 50)
|
||||
|
||||
|
||||
description = f"**Trigger Text:** `{trigger_text}`\n"
|
||||
description += "Custom reaction has been successfully deleted."
|
||||
|
||||
|
||||
return create_embed("Custom Reaction Deleted", description, 0xFF8C00, check_icon)
|
||||
|
||||
|
||||
def create_not_found_embed(reaction_id: int) -> discord.Embed:
|
||||
description = f"**Reaction ID:** `{reaction_id}`\n"
|
||||
description += "No custom reaction found with the provided ID."
|
||||
|
||||
|
||||
return create_embed("Custom Reaction Not Found", description, 0xFF4500, cross_icon)
|
||||
|
||||
|
||||
def create_no_triggers_embed() -> discord.Embed:
|
||||
description = (
|
||||
"There are no custom reactions set up yet.\n\n"
|
||||
|
@ -75,7 +100,10 @@ def create_no_triggers_embed() -> discord.Embed:
|
|||
"**Text Reaction:**\n"
|
||||
"A text reaction will respond with a specific text message when the trigger text is detected."
|
||||
)
|
||||
|
||||
return create_embed("No Custom Reactions Found", description, 0xFF8C00, exclaim_icon)
|
||||
|
||||
|
||||
return create_embed(
|
||||
"No Custom Reactions Found",
|
||||
description,
|
||||
0xFF8C00,
|
||||
exclaim_icon,
|
||||
)
|
||||
|
|
|
@ -16,7 +16,9 @@ class BlackJackButtons(View):
|
|||
await self.message.edit(view=None)
|
||||
|
||||
@discord.ui.button(
|
||||
label="hit", style=discord.ButtonStyle.gray, emoji="<:hit:1119262723285467156> "
|
||||
label="hit",
|
||||
style=discord.ButtonStyle.gray,
|
||||
emoji="<:hit:1119262723285467156> ",
|
||||
)
|
||||
async def hit_button_callback(self, button, interaction):
|
||||
self.clickedHit = True
|
||||
|
@ -36,7 +38,8 @@ class BlackJackButtons(View):
|
|||
async def interaction_check(self, interaction) -> bool:
|
||||
if interaction.user != self.ctx.author:
|
||||
await interaction.response.send_message(
|
||||
"You can't use these buttons, they're someone else's!", ephemeral=True
|
||||
"You can't use these buttons, they're someone else's!",
|
||||
ephemeral=True,
|
||||
)
|
||||
return False
|
||||
else:
|
||||
|
@ -68,7 +71,8 @@ class ExchangeConfirmation(View):
|
|||
async def interaction_check(self, interaction) -> bool:
|
||||
if interaction.user != self.ctx.author:
|
||||
await interaction.response.send_message(
|
||||
"You can't use these buttons, they're someone else's!", ephemeral=True
|
||||
"You can't use these buttons, they're someone else's!",
|
||||
ephemeral=True,
|
||||
)
|
||||
return False
|
||||
else:
|
||||
|
|
|
@ -51,7 +51,9 @@ class IntroductionFinishButtons(View):
|
|||
|
||||
@discord.ui.button(label="Post it!", style=discord.ButtonStyle.green)
|
||||
async def short_button_callback(
|
||||
self, button: discord.ui.Button, interaction: discord.Interaction
|
||||
self,
|
||||
button: discord.ui.Button,
|
||||
interaction: discord.Interaction,
|
||||
) -> None:
|
||||
await interaction.response.edit_message(view=None)
|
||||
self.clickedConfirm = True
|
||||
|
@ -59,7 +61,9 @@ class IntroductionFinishButtons(View):
|
|||
|
||||
@discord.ui.button(label="Stop", style=discord.ButtonStyle.red)
|
||||
async def extended_button_callback(
|
||||
self, button: discord.ui.Button, interaction: discord.Interaction
|
||||
self,
|
||||
button: discord.ui.Button,
|
||||
interaction: discord.Interaction,
|
||||
) -> None:
|
||||
await interaction.response.edit_message(view=None)
|
||||
self.stop()
|
||||
|
@ -67,7 +71,8 @@ class IntroductionFinishButtons(View):
|
|||
async def interaction_check(self, interaction: discord.Interaction) -> bool:
|
||||
if interaction.user != self.ctx.author:
|
||||
await interaction.response.send_message(
|
||||
"You can't use these buttons.", ephemeral=True
|
||||
"You can't use these buttons.",
|
||||
ephemeral=True,
|
||||
)
|
||||
return False
|
||||
else:
|
||||
|
|
|
@ -23,12 +23,14 @@ class ReactionHandler:
|
|||
"My reply is no.",
|
||||
"My sources say no.",
|
||||
"Outlook not so good.",
|
||||
"Very doubtful."
|
||||
"Very doubtful.",
|
||||
]
|
||||
|
||||
async def handle_message(self, message):
|
||||
content = message.content.lower()
|
||||
|
||||
if (content.startswith("Lumi ") or content.startswith("Lumi, ")) and content.endswith("?"):
|
||||
if (
|
||||
content.startswith("Lumi ") or content.startswith("Lumi, ")
|
||||
) and content.endswith("?"):
|
||||
response = random.choice(self.eightball)
|
||||
await message.reply(content=response)
|
||||
|
|
|
@ -4,7 +4,7 @@ import pytz
|
|||
|
||||
|
||||
def seconds_until(hours, minutes):
|
||||
eastern_timezone = pytz.timezone('US/Eastern')
|
||||
eastern_timezone = pytz.timezone("US/Eastern")
|
||||
|
||||
now = datetime.datetime.now(eastern_timezone)
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ class BotAdmin(commands.Cog, name="Bot Admin"):
|
|||
name="award",
|
||||
description="This command can only be performed by a bot administrator.",
|
||||
help="Awards cash to a specific user. This command can only be performed by a bot administrator.",
|
||||
guild_only=True
|
||||
guild_only=True,
|
||||
)
|
||||
@commands.guild_only()
|
||||
@commands.is_owner()
|
||||
|
@ -29,7 +29,7 @@ class BotAdmin(commands.Cog, name="Bot Admin"):
|
|||
name="sqlselect",
|
||||
aliases=["sqls"],
|
||||
description="This command can only be performed by a bot administrator.",
|
||||
help="Perform a SELECT query in the database. This command can only be performed by a bot administrator."
|
||||
help="Perform a SELECT query in the database. This command can only be performed by a bot administrator.",
|
||||
)
|
||||
@commands.is_owner()
|
||||
async def select(self, ctx, *, query: str):
|
||||
|
@ -39,15 +39,15 @@ class BotAdmin(commands.Cog, name="Bot Admin"):
|
|||
name="sqlinject",
|
||||
aliases=["sqli"],
|
||||
description="This command can only be performed by a bot administrator.",
|
||||
help="Change a value in the database. This command can only be performed by a bot administrator."
|
||||
help="Change a value in the database. This command can only be performed by a bot administrator.",
|
||||
)
|
||||
@commands.is_owner()
|
||||
async def inject(self, ctx, *, query: str):
|
||||
return await sql.inject_cmd(ctx, query)
|
||||
|
||||
|
||||
@commands.command(
|
||||
name="blacklist",
|
||||
help="Add or remove a user from the blacklist. This command can only be performed by a bot administrator."
|
||||
help="Add or remove a user from the blacklist. This command can only be performed by a bot administrator.",
|
||||
)
|
||||
@commands.is_owner()
|
||||
async def blacklist(self, ctx, user: discord.User, *, reason: Optional[str] = None):
|
||||
|
|
|
@ -11,7 +11,7 @@ async def cmd(ctx, user: discord.User, amount: int):
|
|||
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.green(),
|
||||
description=f"Awarded **${Currency.format(amount)}** to {user.name}."
|
||||
description=f"Awarded **${Currency.format(amount)}** to {user.name}.",
|
||||
)
|
||||
|
||||
await ctx.respond(embed=embed)
|
||||
|
|
|
@ -9,7 +9,9 @@ hammer_icon = resources["icons"]["hammer"]
|
|||
|
||||
|
||||
async def blacklist_user(
|
||||
ctx, user: discord.User, reason: Optional[str] = None
|
||||
ctx,
|
||||
user: discord.User,
|
||||
reason: Optional[str] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Blacklists a user with an optional reason.
|
||||
|
@ -26,6 +28,9 @@ async def blacklist_user(
|
|||
color=discord.Color.red(),
|
||||
)
|
||||
embed.set_author(name="User Blacklisted", icon_url=hammer_icon)
|
||||
embed.set_footer(text="There is no process to reinstate a blacklisted user. Appeals are not considered.", icon_url=exclaim_icon)
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
embed.set_footer(
|
||||
text="There is no process to reinstate a blacklisted user. Appeals are not considered.",
|
||||
icon_url=exclaim_icon,
|
||||
)
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
|
|
|
@ -12,7 +12,10 @@ async def select_cmd(ctx, query: str):
|
|||
except sqlite3.Error as error:
|
||||
results = error
|
||||
|
||||
return await ctx.respond(content=f"```SELECT {query}```\n```{results}```", ephemeral=True)
|
||||
return await ctx.respond(
|
||||
content=f"```SELECT {query}```\n```{results}```",
|
||||
ephemeral=True,
|
||||
)
|
||||
|
||||
|
||||
async def inject_cmd(ctx, query: str):
|
||||
|
@ -20,4 +23,7 @@ async def inject_cmd(ctx, query: str):
|
|||
database.execute_query(query)
|
||||
await ctx.respond(content=f"That worked!\n```{query}```", ephemeral=True)
|
||||
except sqlite3.Error as error:
|
||||
await ctx.respond(content=f"Query:\n```{query}```\nError message:\n```{error}```", ephemeral=True)
|
||||
await ctx.respond(
|
||||
content=f"Query:\n```{query}```\nError message:\n```{error}```",
|
||||
ephemeral=True,
|
||||
)
|
||||
|
|
|
@ -12,6 +12,7 @@ from modules.birthdays import birthday
|
|||
from services.birthday_service import Birthday
|
||||
from services.config_service import GuildConfig
|
||||
|
||||
|
||||
class Birthdays(commands.Cog):
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
|
@ -20,11 +21,20 @@ class Birthdays(commands.Cog):
|
|||
"""
|
||||
birthday module - slash command only
|
||||
"""
|
||||
birthday = SlashCommandGroup(name="birthday", description="Birthday commands.", guild_only=True)
|
||||
birthday = SlashCommandGroup(
|
||||
name="birthday",
|
||||
description="Birthday commands.",
|
||||
guild_only=True,
|
||||
)
|
||||
|
||||
@birthday.command(name="set", description="Set your birthday in this server.")
|
||||
@checks.birthdays_enabled()
|
||||
async def set_birthday(self, ctx, month: discord.Option(choices=CONST.BIRTHDAY_MONTHS), day: int):
|
||||
async def set_birthday(
|
||||
self,
|
||||
ctx,
|
||||
month: discord.Option(choices=CONST.BIRTHDAY_MONTHS),
|
||||
day: int,
|
||||
):
|
||||
index = CONST.BIRTHDAY_MONTHS.index(month) + 1
|
||||
await birthday.add(ctx, month, index, day)
|
||||
|
||||
|
@ -33,16 +43,20 @@ class Birthdays(commands.Cog):
|
|||
async def delete_birthday(self, ctx):
|
||||
await birthday.delete(ctx)
|
||||
|
||||
@birthday.command(name="upcoming", description="Shows the upcoming birthdays in this server.")
|
||||
@birthday.command(
|
||||
name="upcoming",
|
||||
description="Shows the upcoming birthdays in this server.",
|
||||
)
|
||||
@checks.birthdays_enabled()
|
||||
async def upcoming_birthdays(self, ctx):
|
||||
await birthday.upcoming(ctx)
|
||||
|
||||
@tasks.loop(hours=23, minutes=55)
|
||||
async def daily_birthday_check(self):
|
||||
|
||||
wait_time = time.seconds_until(7, 0)
|
||||
logger.debug(f"Waiting until 7 AM Eastern for the daily birthday check: {round(wait_time)}s left.")
|
||||
logger.debug(
|
||||
f"Waiting until 7 AM Eastern for the daily birthday check: {round(wait_time)}s left.",
|
||||
)
|
||||
await asyncio.sleep(wait_time)
|
||||
|
||||
embed = discord.Embed(color=discord.Color.embed_background())
|
||||
|
@ -55,17 +69,26 @@ class Birthdays(commands.Cog):
|
|||
guild_config = GuildConfig(guild.id)
|
||||
|
||||
if not guild_config.birthday_channel_id:
|
||||
logger.debug(f"Birthday announcements in guild with ID {guild.id} skipped: no birthday channel.")
|
||||
logger.debug(
|
||||
f"Birthday announcements in guild with ID {guild.id} skipped: no birthday channel.",
|
||||
)
|
||||
return
|
||||
|
||||
message = random.choice(CONST.BIRTHDAY_MESSAGES)
|
||||
embed.description = message.format(member.name)
|
||||
channel = await self.client.get_or_fetch_channel(guild, guild_config.birthday_channel_id)
|
||||
channel = await self.client.get_or_fetch_channel(
|
||||
guild,
|
||||
guild_config.birthday_channel_id,
|
||||
)
|
||||
await channel.send(embed=embed, content=member.mention)
|
||||
logger.debug(f"Birthday announcement Success! user/guild/chan ID: {member.id}/{guild.id}/{channel.id}")
|
||||
logger.debug(
|
||||
f"Birthday announcement Success! user/guild/chan ID: {member.id}/{guild.id}/{channel.id}",
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"Birthday announcement skipped processing user/guild {user_id}/{guild_id} | {e}")
|
||||
logger.warning(
|
||||
f"Birthday announcement skipped processing user/guild {user_id}/{guild_id} | {e}",
|
||||
)
|
||||
|
||||
# wait one second to avoid rate limits
|
||||
await asyncio.sleep(1)
|
||||
|
|
|
@ -17,7 +17,7 @@ async def add(ctx, month, month_index, day):
|
|||
raise commands.BadArgument("the date you entered is invalid.")
|
||||
|
||||
date_str = f"{leap_year}-{month_index:02d}-{day:02d}"
|
||||
date_obj = datetime.datetime.strptime(date_str, '%Y-%m-%d')
|
||||
date_obj = datetime.datetime.strptime(date_str, "%Y-%m-%d")
|
||||
|
||||
birthday = Birthday(ctx.author.id, ctx.guild.id)
|
||||
birthday.set(date_obj)
|
||||
|
@ -38,7 +38,7 @@ async def upcoming(ctx):
|
|||
icon = ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.embed_background()
|
||||
color=discord.Color.embed_background(),
|
||||
)
|
||||
embed.set_author(name="Upcoming Birthdays!", icon_url=icon)
|
||||
embed.set_thumbnail(url="https://i.imgur.com/79XfsbS.png")
|
||||
|
@ -61,7 +61,7 @@ async def upcoming(ctx):
|
|||
embed.add_field(
|
||||
name=f"{name}",
|
||||
value=f"🎂 {formatted_birthday}",
|
||||
inline=False
|
||||
inline=False,
|
||||
)
|
||||
|
||||
found_birthdays += 1
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
|
||||
|
||||
import discord
|
||||
from discord.commands import SlashCommandGroup
|
||||
from discord.ext import commands, bridge
|
||||
|
@ -24,8 +22,8 @@ class Config(commands.Cog):
|
|||
aliases=["config"],
|
||||
description="Show your server configuration.",
|
||||
help="Shows information about how Lumi is configured in your server. "
|
||||
"[Read the guide](https://wiki.wlinator.org/serverconfig).",
|
||||
guild_only=True
|
||||
"[Read the guide](https://wiki.wlinator.org/serverconfig).",
|
||||
guild_only=True,
|
||||
)
|
||||
@commands.guild_only()
|
||||
@commands.has_permissions(manage_channels=True)
|
||||
|
@ -37,7 +35,7 @@ class Config(commands.Cog):
|
|||
aliases=["sp"],
|
||||
description="Set Lumi's prefix.",
|
||||
help="Set the prefix for Lumi in this server. The maximum length of a prefix is 25.",
|
||||
guild_only=True
|
||||
guild_only=True,
|
||||
)
|
||||
@commands.guild_only()
|
||||
@commands.has_permissions(manage_channels=True)
|
||||
|
@ -49,7 +47,7 @@ class Config(commands.Cog):
|
|||
aliases=["xpr"],
|
||||
description="Show your server's XP rewards list.",
|
||||
help="Read [the guide](https://wiki.wlinator.org/xprewards) before editing.",
|
||||
guild_only="True"
|
||||
guild_only="True",
|
||||
)
|
||||
@commands.guild_only()
|
||||
@commands.has_permissions(manage_roles=True)
|
||||
|
@ -61,11 +59,17 @@ class Config(commands.Cog):
|
|||
aliases=["axpr"],
|
||||
description="Add a Lumi XP reward.",
|
||||
help="Add a Lumi XP reward. Read [the guide](https://wiki.wlinator.org/xprewards) before editing.",
|
||||
guild_only="True"
|
||||
guild_only="True",
|
||||
)
|
||||
@commands.guild_only()
|
||||
@commands.has_permissions(manage_roles=True)
|
||||
async def xp_reward_command_add(self, ctx, level: int, role: discord.Role, persistent: bool = False):
|
||||
async def xp_reward_command_add(
|
||||
self,
|
||||
ctx,
|
||||
level: int,
|
||||
role: discord.Role,
|
||||
persistent: bool = False,
|
||||
):
|
||||
await xp_reward.add_reward(ctx, level, role.id, persistent)
|
||||
|
||||
@bridge.bridge_command(
|
||||
|
@ -73,7 +77,7 @@ class Config(commands.Cog):
|
|||
aliases=["rxpr"],
|
||||
description="Remove a Lumi XP reward.",
|
||||
help="Remove a Lumi XP reward. Read [the guide](https://wiki.wlinator.org/xprewards) before editing.",
|
||||
guild_only="True"
|
||||
guild_only="True",
|
||||
)
|
||||
@commands.guild_only()
|
||||
@commands.has_permissions(manage_roles=True)
|
||||
|
@ -83,8 +87,12 @@ class Config(commands.Cog):
|
|||
"""
|
||||
The guild config code is a mess.
|
||||
"""
|
||||
config = SlashCommandGroup("config", "server config commands.", guild_only=True,
|
||||
default_member_permissions=discord.Permissions(manage_channels=True))
|
||||
config = SlashCommandGroup(
|
||||
"config",
|
||||
"server config commands.",
|
||||
guild_only=True,
|
||||
default_member_permissions=discord.Permissions(manage_channels=True),
|
||||
)
|
||||
birthday_config = config.create_subgroup(name="birthdays")
|
||||
command_config = config.create_subgroup(name="commands")
|
||||
intro_config = config.create_subgroup(name="intros")
|
||||
|
@ -94,7 +102,7 @@ class Config(commands.Cog):
|
|||
|
||||
@birthday_config.command(
|
||||
name="channel",
|
||||
description="Set the birthday announcements channel."
|
||||
description="Set the birthday announcements channel.",
|
||||
)
|
||||
async def config_birthdays_channel(self, ctx, *, channel: discord.TextChannel):
|
||||
guild_config = GuildConfig(ctx.guild.id)
|
||||
|
@ -103,9 +111,11 @@ class Config(commands.Cog):
|
|||
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.orange(),
|
||||
description=f"✅ | Birthday announcements will be sent in {channel.mention}."
|
||||
description=f"✅ | Birthday announcements will be sent in {channel.mention}.",
|
||||
)
|
||||
guild_icon = (
|
||||
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
)
|
||||
guild_icon = ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
embed.set_author(name="Server Configuration", icon_url=guild_icon)
|
||||
|
||||
return await ctx.respond(embed=embed)
|
||||
|
@ -120,7 +130,9 @@ class Config(commands.Cog):
|
|||
embed = discord.Embed(
|
||||
color=discord.Color.orange(),
|
||||
)
|
||||
guild_icon = ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
guild_icon = (
|
||||
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
)
|
||||
embed.set_author(name="Server Configuration", icon_url=guild_icon)
|
||||
|
||||
if not guild_config.birthday_channel_id:
|
||||
|
@ -135,7 +147,7 @@ class Config(commands.Cog):
|
|||
|
||||
@command_config.command(
|
||||
name="channel",
|
||||
description="Configure where members can use Lumi commands."
|
||||
description="Configure where members can use Lumi commands.",
|
||||
)
|
||||
async def config_commands_channel(self, ctx, *, channel: discord.TextChannel):
|
||||
guild_config = GuildConfig(ctx.guild.id)
|
||||
|
@ -144,17 +156,21 @@ class Config(commands.Cog):
|
|||
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.orange(),
|
||||
description=f"✅ | Commands can now only be used in {channel.mention}."
|
||||
description=f"✅ | Commands can now only be used in {channel.mention}.",
|
||||
)
|
||||
guild_icon = (
|
||||
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
)
|
||||
guild_icon = ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
embed.set_author(name="Server Configuration", icon_url=guild_icon)
|
||||
embed.set_footer(text="Note: mod & config commands are still available everywhere.")
|
||||
embed.set_footer(
|
||||
text="Note: mod & config commands are still available everywhere.",
|
||||
)
|
||||
|
||||
return await ctx.respond(embed=embed)
|
||||
|
||||
@command_config.command(
|
||||
name="everywhere",
|
||||
description="Allow members to do commands in all channels."
|
||||
description="Allow members to do commands in all channels.",
|
||||
)
|
||||
async def config_commands_everywhere(self, ctx):
|
||||
guild_config = GuildConfig(ctx.guild.id)
|
||||
|
@ -163,9 +179,11 @@ class Config(commands.Cog):
|
|||
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.orange(),
|
||||
description="✅ | Server members can now use Lumi commands in all channels. "
|
||||
description="✅ | Server members can now use Lumi commands in all channels. ",
|
||||
)
|
||||
guild_icon = (
|
||||
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
)
|
||||
guild_icon = ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
embed.set_author(name="Server Configuration", icon_url=guild_icon)
|
||||
|
||||
return await ctx.respond(embed=embed)
|
||||
|
@ -213,7 +231,7 @@ class Config(commands.Cog):
|
|||
|
||||
@welcome_config.command(
|
||||
name="channel",
|
||||
description="Set the greeting announcements channel."
|
||||
description="Set the greeting announcements channel.",
|
||||
)
|
||||
async def config_welcome_channel(self, ctx, *, channel: discord.TextChannel):
|
||||
guild_config = GuildConfig(ctx.guild.id)
|
||||
|
@ -222,16 +240,18 @@ class Config(commands.Cog):
|
|||
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.orange(),
|
||||
description=f"✅ | New members will receive a welcome message in {channel.mention}."
|
||||
description=f"✅ | New members will receive a welcome message in {channel.mention}.",
|
||||
)
|
||||
guild_icon = (
|
||||
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
)
|
||||
guild_icon = ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
embed.set_author(name="Server Configuration", icon_url=guild_icon)
|
||||
|
||||
return await ctx.respond(embed=embed)
|
||||
|
||||
@welcome_config.command(
|
||||
name="disable",
|
||||
description="Disable greetings in this server."
|
||||
description="Disable greetings in this server.",
|
||||
)
|
||||
async def config_welcome_disable(self, ctx):
|
||||
guild_config = GuildConfig(ctx.guild.id)
|
||||
|
@ -239,7 +259,9 @@ class Config(commands.Cog):
|
|||
embed = discord.Embed(
|
||||
color=discord.Color.orange(),
|
||||
)
|
||||
guild_icon = ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
guild_icon = (
|
||||
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
)
|
||||
embed.set_author(name="Server Configuration", icon_url=guild_icon)
|
||||
|
||||
if not guild_config.welcome_channel_id:
|
||||
|
@ -255,20 +277,31 @@ class Config(commands.Cog):
|
|||
|
||||
@welcome_config.command(
|
||||
name="template",
|
||||
description="Make a custom greeting template."
|
||||
description="Make a custom greeting template.",
|
||||
)
|
||||
async def config_welcome_template(self, ctx, *, text: discord.Option(str, max_length=2000)):
|
||||
async def config_welcome_template(
|
||||
self,
|
||||
ctx,
|
||||
*,
|
||||
text: discord.Option(str, max_length=2000),
|
||||
):
|
||||
guild_config = GuildConfig(ctx.guild.id)
|
||||
guild_config.welcome_message = text
|
||||
guild_config.push()
|
||||
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.orange(),
|
||||
description="✅ | The greeting template was successfully updated."
|
||||
description="✅ | The greeting template was successfully updated.",
|
||||
)
|
||||
guild_icon = (
|
||||
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
)
|
||||
guild_icon = ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
embed.add_field(name="Template", value=text, inline=False)
|
||||
embed.add_field(name="Example", value="An example will be sent in a separate message.", inline=False)
|
||||
embed.add_field(
|
||||
name="Example",
|
||||
value="An example will be sent in a separate message.",
|
||||
inline=False,
|
||||
)
|
||||
embed.set_author(name="Server Configuration", icon_url=guild_icon)
|
||||
await ctx.respond(embed=embed)
|
||||
|
||||
|
@ -277,7 +310,7 @@ class Config(commands.Cog):
|
|||
|
||||
@boost_config.command(
|
||||
name="channel",
|
||||
description="Set the boost announcements channel."
|
||||
description="Set the boost announcements channel.",
|
||||
)
|
||||
async def config_boosts_channel(self, ctx, *, channel: discord.TextChannel):
|
||||
guild_config = GuildConfig(ctx.guild.id)
|
||||
|
@ -286,16 +319,18 @@ class Config(commands.Cog):
|
|||
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.orange(),
|
||||
description=f"✅ | I will announce server boosts in {channel.mention}."
|
||||
description=f"✅ | I will announce server boosts in {channel.mention}.",
|
||||
)
|
||||
guild_icon = (
|
||||
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
)
|
||||
guild_icon = ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
embed.set_author(name="Server Configuration", icon_url=guild_icon)
|
||||
|
||||
return await ctx.respond(embed=embed)
|
||||
|
||||
@boost_config.command(
|
||||
name="disable",
|
||||
description="Disable boost announcements in this server."
|
||||
description="Disable boost announcements in this server.",
|
||||
)
|
||||
async def config_boosts_disable(self, ctx):
|
||||
guild_config = GuildConfig(ctx.guild.id)
|
||||
|
@ -303,7 +338,9 @@ class Config(commands.Cog):
|
|||
embed = discord.Embed(
|
||||
color=discord.Color.orange(),
|
||||
)
|
||||
guild_icon = ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
guild_icon = (
|
||||
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
)
|
||||
embed.set_author(name="Server Configuration", icon_url=guild_icon)
|
||||
|
||||
if not guild_config.boost_channel_id:
|
||||
|
@ -319,20 +356,31 @@ class Config(commands.Cog):
|
|||
|
||||
@boost_config.command(
|
||||
name="template",
|
||||
description="Make a custom boost announcement template."
|
||||
description="Make a custom boost announcement template.",
|
||||
)
|
||||
async def config_boosts_template(self, ctx, *, text: discord.Option(str, max_length=2000)):
|
||||
async def config_boosts_template(
|
||||
self,
|
||||
ctx,
|
||||
*,
|
||||
text: discord.Option(str, max_length=2000),
|
||||
):
|
||||
guild_config = GuildConfig(ctx.guild.id)
|
||||
guild_config.boost_message = text
|
||||
guild_config.push()
|
||||
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.orange(),
|
||||
description="✅ | The booster template was successfully updated."
|
||||
description="✅ | The booster template was successfully updated.",
|
||||
)
|
||||
guild_icon = (
|
||||
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
)
|
||||
guild_icon = ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
embed.add_field(name="Template", value=text, inline=False)
|
||||
embed.add_field(name="Example", value="An example will be sent in a separate message.", inline=False)
|
||||
embed.add_field(
|
||||
name="Example",
|
||||
value="An example will be sent in a separate message.",
|
||||
inline=False,
|
||||
)
|
||||
embed.set_author(name="Server Configuration", icon_url=guild_icon)
|
||||
await ctx.respond(embed=embed)
|
||||
|
||||
|
@ -341,7 +389,7 @@ class Config(commands.Cog):
|
|||
|
||||
@boost_config.command(
|
||||
name="image",
|
||||
description="Add a custom image that will used for booster announcements."
|
||||
description="Add a custom image that will used for booster announcements.",
|
||||
)
|
||||
async def config_boosts_image(self, ctx, *, image_url: str):
|
||||
guild_config = GuildConfig(ctx.guild.id)
|
||||
|
@ -354,7 +402,9 @@ class Config(commands.Cog):
|
|||
elif not image_url.endswith(".jpg") and not image_url.lower().endswith(".png"):
|
||||
return await ctx.respond(embed=GenericErrors.bad_url(ctx))
|
||||
|
||||
elif not image_url.startswith("http://") and not image_url.startswith("https://"):
|
||||
elif not image_url.startswith("http://") and not image_url.startswith(
|
||||
"https://",
|
||||
):
|
||||
return await ctx.respond(embed=GenericErrors.bad_url(ctx, "invalid URL."))
|
||||
|
||||
else:
|
||||
|
@ -363,11 +413,21 @@ class Config(commands.Cog):
|
|||
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.orange(),
|
||||
description="✅ | The booster image was successfully updated."
|
||||
description="✅ | The booster image was successfully updated.",
|
||||
)
|
||||
guild_icon = (
|
||||
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
)
|
||||
embed.add_field(
|
||||
name="Image",
|
||||
value=image_url if image_url else "Original Image",
|
||||
inline=False,
|
||||
)
|
||||
embed.add_field(
|
||||
name="Example",
|
||||
value="An example will be sent in a separate message.",
|
||||
inline=False,
|
||||
)
|
||||
guild_icon = ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
embed.add_field(name="Image", value=image_url if image_url else "Original Image", inline=False)
|
||||
embed.add_field(name="Example", value="An example will be sent in a separate message.", inline=False)
|
||||
embed.set_author(name="Server Configuration", icon_url=guild_icon)
|
||||
await ctx.respond(embed=embed)
|
||||
|
||||
|
@ -376,7 +436,7 @@ class Config(commands.Cog):
|
|||
|
||||
@level_config.command(
|
||||
name="channel",
|
||||
description="Set the level announcements channel."
|
||||
description="Set the level announcements channel.",
|
||||
)
|
||||
async def config_level_channel(self, ctx, *, channel: discord.TextChannel):
|
||||
guild_config = GuildConfig(ctx.guild.id)
|
||||
|
@ -385,19 +445,23 @@ class Config(commands.Cog):
|
|||
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.orange(),
|
||||
description=f"✅ | All level announcements will be sent in {channel.mention}."
|
||||
description=f"✅ | All level announcements will be sent in {channel.mention}.",
|
||||
)
|
||||
guild_icon = (
|
||||
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
)
|
||||
guild_icon = ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
embed.set_author(name="Server Configuration", icon_url=guild_icon)
|
||||
|
||||
if guild_config.level_message_type == 0:
|
||||
embed.set_footer(text="Warning: this module is disabled, please do '/config levels enable'")
|
||||
embed.set_footer(
|
||||
text="Warning: this module is disabled, please do '/config levels enable'",
|
||||
)
|
||||
|
||||
return await ctx.respond(embed=embed)
|
||||
|
||||
@level_config.command(
|
||||
name="currentchannel",
|
||||
description="Send level announcements in the member's current channel."
|
||||
description="Send level announcements in the member's current channel.",
|
||||
)
|
||||
async def config_level_samechannel(self, ctx):
|
||||
guild_config = GuildConfig(ctx.guild.id)
|
||||
|
@ -406,19 +470,23 @@ class Config(commands.Cog):
|
|||
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.orange(),
|
||||
description="✅ | Members will receive level announcements in their current channel."
|
||||
description="✅ | Members will receive level announcements in their current channel.",
|
||||
)
|
||||
guild_icon = (
|
||||
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
)
|
||||
guild_icon = ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
embed.set_author(name="Server Configuration", icon_url=guild_icon)
|
||||
|
||||
if guild_config.level_message_type == 0:
|
||||
embed.set_footer(text="Warning: this module is disabled, please do '/config levels enable'")
|
||||
embed.set_footer(
|
||||
text="Warning: this module is disabled, please do '/config levels enable'",
|
||||
)
|
||||
|
||||
return await ctx.respond(embed=embed)
|
||||
|
||||
@level_config.command(
|
||||
name="disable",
|
||||
description="Disable levels and the Lumi XP system."
|
||||
description="Disable levels and the Lumi XP system.",
|
||||
)
|
||||
async def config_level_disable(self, ctx):
|
||||
guild_config = GuildConfig(ctx.guild.id)
|
||||
|
@ -427,16 +495,18 @@ class Config(commands.Cog):
|
|||
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.orange(),
|
||||
description="✅ | The Lumi XP system was successfully disabled."
|
||||
description="✅ | The Lumi XP system was successfully disabled.",
|
||||
)
|
||||
guild_icon = (
|
||||
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
)
|
||||
guild_icon = ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
embed.set_author(name="Server Configuration", icon_url=guild_icon)
|
||||
|
||||
return await ctx.respond(embed=embed)
|
||||
|
||||
@level_config.command(
|
||||
name="enable",
|
||||
description="Enable levels and the Lumi XP system."
|
||||
description="Enable levels and the Lumi XP system.",
|
||||
)
|
||||
async def config_level_enable(self, ctx):
|
||||
guild_config = GuildConfig(ctx.guild.id)
|
||||
|
@ -444,7 +514,9 @@ class Config(commands.Cog):
|
|||
embed = discord.Embed(
|
||||
color=discord.Color.orange(),
|
||||
)
|
||||
guild_icon = ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
guild_icon = (
|
||||
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
)
|
||||
embed.set_author(name="Server Configuration", icon_url=guild_icon)
|
||||
|
||||
if guild_config.level_message_type != 0:
|
||||
|
@ -460,15 +532,22 @@ class Config(commands.Cog):
|
|||
|
||||
@level_config.command(
|
||||
name="type",
|
||||
description="Set the level announcements type."
|
||||
description="Set the level announcements type.",
|
||||
)
|
||||
async def config_level_type(self, ctx, *, type: discord.Option(choices=["whimsical", "generic"])):
|
||||
async def config_level_type(
|
||||
self,
|
||||
ctx,
|
||||
*,
|
||||
type: discord.Option(choices=["whimsical", "generic"]),
|
||||
):
|
||||
guild_config = GuildConfig(ctx.guild.id)
|
||||
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.orange(),
|
||||
)
|
||||
guild_icon = ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
guild_icon = (
|
||||
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
)
|
||||
embed.set_author(name="Server Configuration", icon_url=guild_icon)
|
||||
|
||||
if type == "whimsical":
|
||||
|
@ -477,8 +556,11 @@ class Config(commands.Cog):
|
|||
guild_config.push()
|
||||
|
||||
embed.description = "✅ | Level announcements will be sarcastic comments."
|
||||
embed.add_field(name="Example", value="📈 | **lucas** Lol it took you this long to reach **Level 15**.",
|
||||
inline=False)
|
||||
embed.add_field(
|
||||
name="Example",
|
||||
value="📈 | **lucas** Lol it took you this long to reach **Level 15**.",
|
||||
inline=False,
|
||||
)
|
||||
return await ctx.respond(embed=embed)
|
||||
|
||||
else:
|
||||
|
@ -487,14 +569,23 @@ class Config(commands.Cog):
|
|||
guild_config.push()
|
||||
|
||||
embed.description = "✅ | Level announcements will be generic messages."
|
||||
embed.add_field(name="Example", value="📈 | **lucas** you have reached **Level 15**.", inline=False)
|
||||
embed.add_field(
|
||||
name="Example",
|
||||
value="📈 | **lucas** you have reached **Level 15**.",
|
||||
inline=False,
|
||||
)
|
||||
return await ctx.respond(embed=embed)
|
||||
|
||||
@level_config.command(
|
||||
name="template",
|
||||
description="Make a custom leveling template."
|
||||
description="Make a custom leveling template.",
|
||||
)
|
||||
async def config_level_template(self, ctx, *, text: discord.Option(str, max_length=2000)):
|
||||
async def config_level_template(
|
||||
self,
|
||||
ctx,
|
||||
*,
|
||||
text: discord.Option(str, max_length=2000),
|
||||
):
|
||||
guild_config = GuildConfig(ctx.guild.id)
|
||||
guild_config.level_message = text
|
||||
guild_config.push()
|
||||
|
@ -503,15 +594,19 @@ class Config(commands.Cog):
|
|||
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.orange(),
|
||||
description="✅ | The level template was successfully updated."
|
||||
description="✅ | The level template was successfully updated.",
|
||||
)
|
||||
guild_icon = (
|
||||
ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
)
|
||||
guild_icon = ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
embed.add_field(name="Template", value=text, inline=False)
|
||||
embed.add_field(name="Example", value=preview, inline=False)
|
||||
embed.set_author(name="Server Configuration", icon_url=guild_icon)
|
||||
|
||||
if guild_config.level_message_type == 0:
|
||||
embed.set_footer(text="Warning: this module is disabled, please do '/config levels enable'")
|
||||
embed.set_footer(
|
||||
text="Warning: this module is disabled, please do '/config levels enable'",
|
||||
)
|
||||
|
||||
return await ctx.respond(embed=embed)
|
||||
|
||||
|
|
|
@ -11,14 +11,17 @@ async def cmd(self, ctx):
|
|||
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.embed_background(),
|
||||
description="Guide: https://wiki.wlinator.org/serverconfig"
|
||||
description="Guide: https://wiki.wlinator.org/serverconfig",
|
||||
)
|
||||
icon = ctx.guild.icon if ctx.guild.icon else "https://i.imgur.com/79XfsbS.png"
|
||||
embed.set_author(name=f"{ctx.guild.name} config", icon_url=icon)
|
||||
|
||||
# birthdays
|
||||
if guild_config.birthday_channel_id:
|
||||
channel = await self.client.get_or_fetch_channel(ctx.guild, guild_config.birthday_channel_id)
|
||||
channel = await self.client.get_or_fetch_channel(
|
||||
ctx.guild,
|
||||
guild_config.birthday_channel_id,
|
||||
)
|
||||
|
||||
if channel:
|
||||
birthday_config = f"✅ | in {channel.mention}."
|
||||
|
@ -32,7 +35,10 @@ async def cmd(self, ctx):
|
|||
|
||||
# commands
|
||||
if guild_config.command_channel_id:
|
||||
channel = await self.client.get_or_fetch_channel(ctx.guild, guild_config.command_channel_id)
|
||||
channel = await self.client.get_or_fetch_channel(
|
||||
ctx.guild,
|
||||
guild_config.command_channel_id,
|
||||
)
|
||||
|
||||
if channel:
|
||||
commands_config = f"✅ | commands only allowed in {channel.mention}."
|
||||
|
@ -45,13 +51,18 @@ async def cmd(self, ctx):
|
|||
|
||||
# greetings
|
||||
if guild_config.welcome_channel_id:
|
||||
channel = await self.client.get_or_fetch_channel(ctx.guild, guild_config.welcome_channel_id)
|
||||
channel = await self.client.get_or_fetch_channel(
|
||||
ctx.guild,
|
||||
guild_config.welcome_channel_id,
|
||||
)
|
||||
|
||||
if channel:
|
||||
greeting_config = f"✅ | in {channel.mention}"
|
||||
|
||||
if guild_config.welcome_message:
|
||||
greeting_config += f" with template:\n```{guild_config.welcome_message}```"
|
||||
greeting_config += (
|
||||
f" with template:\n```{guild_config.welcome_message}```"
|
||||
)
|
||||
else:
|
||||
greeting_config += " without custom template."
|
||||
|
||||
|
@ -64,7 +75,10 @@ async def cmd(self, ctx):
|
|||
|
||||
# boosts
|
||||
if guild_config.boost_channel_id:
|
||||
channel = await self.client.get_or_fetch_channel(ctx.guild, guild_config.boost_channel_id)
|
||||
channel = await self.client.get_or_fetch_channel(
|
||||
ctx.guild,
|
||||
guild_config.boost_channel_id,
|
||||
)
|
||||
|
||||
if channel:
|
||||
boost_config = f"✅ | in {channel.mention}"
|
||||
|
@ -73,7 +87,9 @@ async def cmd(self, ctx):
|
|||
if guild_config.boost_image_url:
|
||||
boost_config += f" with custom image and template:\n```{guild_config.boost_message}```"
|
||||
else:
|
||||
boost_config += f" with custom template:\n```{guild_config.boost_message}```"
|
||||
boost_config += (
|
||||
f" with custom template:\n```{guild_config.boost_message}```"
|
||||
)
|
||||
else:
|
||||
if guild_config.boost_image_url:
|
||||
boost_config += " with custom image, but no template."
|
||||
|
@ -98,7 +114,10 @@ async def cmd(self, ctx):
|
|||
level_config = "✅ | generic announcements"
|
||||
|
||||
if guild_config.level_channel_id and guild_config.level_message_type != 0:
|
||||
channel = await self.client.get_or_fetch_channel(ctx.guild, guild_config.level_channel_id)
|
||||
channel = await self.client.get_or_fetch_channel(
|
||||
ctx.guild,
|
||||
guild_config.level_channel_id,
|
||||
)
|
||||
|
||||
if channel:
|
||||
level_config += f" in {channel.mention}"
|
||||
|
|
|
@ -7,7 +7,9 @@ async def set_cmd(ctx, prefix):
|
|||
if len(prefix) > 25:
|
||||
return await ctx.respond(embed=MiscErrors.prefix_too_long(ctx))
|
||||
|
||||
guild_config = GuildConfig(ctx.guild.id) # generate a guild_config for if it didn't already exist
|
||||
guild_config = GuildConfig(
|
||||
ctx.guild.id,
|
||||
) # generate a guild_config for if it didn't already exist
|
||||
GuildConfig.set_prefix(guild_config.guild_id, prefix)
|
||||
|
||||
await ctx.respond(embed=MiscInfo.set_prefix(ctx, prefix))
|
||||
|
|
|
@ -11,7 +11,7 @@ async def show(ctx):
|
|||
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.embed_background(),
|
||||
description="Read [the guide](https://wiki.wlinator.org/xprewards) before editing.\n"
|
||||
description="Read [the guide](https://wiki.wlinator.org/xprewards) before editing.\n",
|
||||
)
|
||||
|
||||
icon = ctx.guild.icon if ctx.guild.icon else art["logo"]["opaque"]
|
||||
|
@ -21,7 +21,9 @@ async def show(ctx):
|
|||
role_id, persistent = level_reward.rewards.get(level)
|
||||
role = ctx.guild.get_role(role_id)
|
||||
|
||||
embed.description += f"\n**Level {level}** -> {role.mention if role else 'Role not found'}"
|
||||
embed.description += (
|
||||
f"\n**Level {level}** -> {role.mention if role else 'Role not found'}"
|
||||
)
|
||||
|
||||
if bool(persistent):
|
||||
embed.description += " (persistent)"
|
||||
|
|
|
@ -48,7 +48,9 @@ class Economy(commands.Cog):
|
|||
return await daily.cmd(ctx)
|
||||
|
||||
@commands.slash_command(
|
||||
name="give", description="Give a server member some cash.", guild_only=True
|
||||
name="give",
|
||||
description="Give a server member some cash.",
|
||||
guild_only=True,
|
||||
)
|
||||
@commands.guild_only()
|
||||
@checks.allowed_in_channel()
|
||||
|
|
|
@ -11,7 +11,7 @@ async def cmd(ctx):
|
|||
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.embed_background(),
|
||||
description=f"**Cash**: ${balance}"
|
||||
description=f"**Cash**: ${balance}",
|
||||
)
|
||||
embed.set_author(name=f"{ctx.author.name}'s wallet", icon_url=ctx.author.avatar.url)
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ from services.currency_service import Currency
|
|||
from services.stats_service import BlackJackStats
|
||||
|
||||
resources = JsonCache.read_json("resources")
|
||||
est = pytz.timezone('US/Eastern')
|
||||
est = pytz.timezone("US/Eastern")
|
||||
active_blackjack_games = {}
|
||||
|
||||
|
||||
|
@ -48,7 +48,6 @@ async def cmd(ctx, bet: int):
|
|||
active_blackjack_games[ctx.author.id] = True
|
||||
|
||||
try:
|
||||
|
||||
player_hand = []
|
||||
dealer_hand = []
|
||||
deck = get_new_deck()
|
||||
|
@ -69,11 +68,18 @@ async def cmd(ctx, bet: int):
|
|||
|
||||
while status == 0:
|
||||
if not playing_embed:
|
||||
await ctx.respond(embed=blackjack_show(ctx, Currency.format_human(bet), player_hand,
|
||||
dealer_hand, player_hand_value,
|
||||
dealer_hand_value),
|
||||
view=view,
|
||||
content=ctx.author.mention)
|
||||
await ctx.respond(
|
||||
embed=blackjack_show(
|
||||
ctx,
|
||||
Currency.format_human(bet),
|
||||
player_hand,
|
||||
dealer_hand,
|
||||
player_hand_value,
|
||||
dealer_hand_value,
|
||||
),
|
||||
view=view,
|
||||
content=ctx.author.mention,
|
||||
)
|
||||
|
||||
playing_embed = True
|
||||
|
||||
|
@ -110,9 +116,14 @@ async def cmd(ctx, bet: int):
|
|||
|
||||
# refresh
|
||||
view = interaction.BlackJackButtons(ctx)
|
||||
embed = blackjack_show(ctx, Currency.format_human(bet), player_hand,
|
||||
dealer_hand, player_hand_value,
|
||||
dealer_hand_value)
|
||||
embed = blackjack_show(
|
||||
ctx,
|
||||
Currency.format_human(bet),
|
||||
player_hand,
|
||||
dealer_hand,
|
||||
player_hand_value,
|
||||
dealer_hand_value,
|
||||
)
|
||||
|
||||
await ctx.edit(embed=embed, view=view, content=ctx.author.mention)
|
||||
|
||||
|
@ -122,8 +133,14 @@ async def cmd(ctx, bet: int):
|
|||
payout = bet * multiplier if not status == 5 else bet * 2
|
||||
is_won = False if status == 1 or status == 4 else True
|
||||
|
||||
embed = blackjack_finished(ctx, Currency.format_human(bet), player_hand_value,
|
||||
dealer_hand_value, Currency.format_human(payout), status)
|
||||
embed = blackjack_finished(
|
||||
ctx,
|
||||
Currency.format_human(bet),
|
||||
player_hand_value,
|
||||
dealer_hand_value,
|
||||
Currency.format_human(payout),
|
||||
status,
|
||||
)
|
||||
|
||||
if playing_embed:
|
||||
await ctx.edit(embed=embed, view=None, content=ctx.author.mention)
|
||||
|
@ -143,12 +160,15 @@ async def cmd(ctx, bet: int):
|
|||
bet=bet,
|
||||
payout=0,
|
||||
hand_player=player_hand,
|
||||
hand_dealer=dealer_hand
|
||||
hand_dealer=dealer_hand,
|
||||
)
|
||||
stats.push()
|
||||
|
||||
elif status == 6:
|
||||
await ctx.send(embed=EconErrors.out_of_time(ctx), content=ctx.author.mention)
|
||||
await ctx.send(
|
||||
embed=EconErrors.out_of_time(ctx),
|
||||
content=ctx.author.mention,
|
||||
)
|
||||
ctx_currency.take_balance(bet)
|
||||
ctx_currency.push()
|
||||
|
||||
|
@ -163,7 +183,7 @@ async def cmd(ctx, bet: int):
|
|||
bet=bet,
|
||||
payout=payout,
|
||||
hand_player=player_hand,
|
||||
hand_dealer=dealer_hand
|
||||
hand_dealer=dealer_hand,
|
||||
)
|
||||
stats.push()
|
||||
|
||||
|
@ -176,30 +196,45 @@ async def cmd(ctx, bet: int):
|
|||
del active_blackjack_games[ctx.author.id]
|
||||
|
||||
|
||||
def blackjack_show(ctx, bet, player_hand, dealer_hand, player_hand_value, dealer_hand_value):
|
||||
def blackjack_show(
|
||||
ctx,
|
||||
bet,
|
||||
player_hand,
|
||||
dealer_hand,
|
||||
player_hand_value,
|
||||
dealer_hand_value,
|
||||
):
|
||||
current_time = datetime.now(est).strftime("%I:%M %p")
|
||||
thumbnail_url = None
|
||||
|
||||
embed = discord.Embed(
|
||||
title="BlackJack",
|
||||
color=discord.Color.dark_orange()
|
||||
color=discord.Color.dark_orange(),
|
||||
)
|
||||
|
||||
embed.description = f"**You**\n" \
|
||||
f"Score: {player_hand_value}\n" \
|
||||
f"*Hand: {' + '.join(player_hand)}*\n\n"
|
||||
embed.description = (
|
||||
f"**You**\n"
|
||||
f"Score: {player_hand_value}\n"
|
||||
f"*Hand: {' + '.join(player_hand)}*\n\n"
|
||||
)
|
||||
|
||||
if len(dealer_hand) < 2:
|
||||
embed.description += f"**Dealer**\n" \
|
||||
f"Score: {dealer_hand_value}\n" \
|
||||
f"*Hand: {dealer_hand[0]} + ??*"
|
||||
embed.description += (
|
||||
f"**Dealer**\n"
|
||||
f"Score: {dealer_hand_value}\n"
|
||||
f"*Hand: {dealer_hand[0]} + ??*"
|
||||
)
|
||||
else:
|
||||
embed.description += f"**Dealer | Score: {dealer_hand_value}**\n" \
|
||||
f"*Hand: {' + '.join(dealer_hand)}*"
|
||||
embed.description += (
|
||||
f"**Dealer | Score: {dealer_hand_value}**\n"
|
||||
f"*Hand: {' + '.join(dealer_hand)}*"
|
||||
)
|
||||
|
||||
embed.set_author(name=ctx.author.name, icon_url=ctx.author.avatar.url)
|
||||
embed.set_footer(text=f"Bet ${bet} • deck shuffled • Today at {current_time}",
|
||||
icon_url="https://i.imgur.com/96jPPXO.png")
|
||||
embed.set_footer(
|
||||
text=f"Bet ${bet} • deck shuffled • Today at {current_time}",
|
||||
icon_url="https://i.imgur.com/96jPPXO.png",
|
||||
)
|
||||
|
||||
if thumbnail_url:
|
||||
embed.set_thumbnail(url=thumbnail_url)
|
||||
|
@ -212,13 +247,16 @@ def blackjack_finished(ctx, bet, player_hand_value, dealer_hand_value, payout, s
|
|||
thumbnail_url = None
|
||||
|
||||
embed = discord.Embed(
|
||||
title="BlackJack"
|
||||
title="BlackJack",
|
||||
)
|
||||
embed.description = (
|
||||
f"You | Score: {player_hand_value}\n" f"Dealer | Score: {dealer_hand_value}"
|
||||
)
|
||||
embed.description = f"You | Score: {player_hand_value}\n" \
|
||||
f"Dealer | Score: {dealer_hand_value}"
|
||||
embed.set_author(name=ctx.author.name, icon_url=ctx.author.avatar.url)
|
||||
embed.set_footer(text=f"Game finished • Today at {current_time}",
|
||||
icon_url="https://i.imgur.com/96jPPXO.png")
|
||||
embed.set_footer(
|
||||
text=f"Game finished • Today at {current_time}",
|
||||
icon_url="https://i.imgur.com/96jPPXO.png",
|
||||
)
|
||||
|
||||
if status == 1:
|
||||
name = "Busted.."
|
||||
|
@ -258,9 +296,11 @@ def blackjack_finished(ctx, bet, player_hand_value, dealer_hand_value, payout, s
|
|||
if thumbnail_url:
|
||||
embed.set_thumbnail(url=thumbnail_url)
|
||||
|
||||
embed.add_field(name=name,
|
||||
value=value,
|
||||
inline=False)
|
||||
embed.add_field(
|
||||
name=name,
|
||||
value=value,
|
||||
inline=False,
|
||||
)
|
||||
embed.colour = color
|
||||
|
||||
return embed
|
||||
|
@ -295,10 +335,10 @@ def calculate_hand_value(hand):
|
|||
if rank.isdigit():
|
||||
value += int(rank)
|
||||
|
||||
elif rank in ['J', 'Q', 'K']:
|
||||
elif rank in ["J", "Q", "K"]:
|
||||
value += 10
|
||||
|
||||
elif rank == 'A':
|
||||
elif rank == "A":
|
||||
value += 11
|
||||
has_ace = True
|
||||
aces_count += 1
|
||||
|
|
|
@ -17,7 +17,7 @@ async def cmd(ctx) -> None:
|
|||
ctx,
|
||||
author_text=CONST.STRINGS["daily_already_claimed_author"],
|
||||
description=CONST.STRINGS["daily_already_claimed_description"].format(
|
||||
unix_time
|
||||
unix_time,
|
||||
),
|
||||
footer_text=CONST.STRINGS["daily_already_claimed_footer"],
|
||||
)
|
||||
|
@ -33,7 +33,7 @@ async def cmd(ctx) -> None:
|
|||
ctx,
|
||||
author_text=CONST.STRINGS["daily_success_claim_author"],
|
||||
description=CONST.STRINGS["daily_success_claim_description"].format(
|
||||
Currency.format(ctx_daily.amount)
|
||||
Currency.format(ctx_daily.amount),
|
||||
),
|
||||
footer_text=CONST.STRINGS["daily_streak_footer"].format(ctx_daily.streak)
|
||||
if ctx_daily.streak > 1
|
||||
|
|
|
@ -29,7 +29,7 @@ async def cmd(ctx, user, amount):
|
|||
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.green(),
|
||||
description=f"**{ctx.author.name}** gave **${Currency.format(amount)}** to {user.name}."
|
||||
description=f"**{ctx.author.name}** gave **${Currency.format(amount)}** to {user.name}.",
|
||||
)
|
||||
|
||||
await ctx.respond(embed=embed)
|
||||
|
|
|
@ -11,13 +11,12 @@ async def cmd(self, ctx):
|
|||
|
||||
embed = discord.Embed(
|
||||
color=discord.Color.embed_background(),
|
||||
description=description
|
||||
description=description,
|
||||
)
|
||||
embed.set_author(name=ctx.author.name, icon_url=ctx.author.avatar.url)
|
||||
|
||||
for item, quantity in inventory_dict.items():
|
||||
if item.type == "badge":
|
||||
|
||||
if not embed.description:
|
||||
embed.description = "**Badges:** "
|
||||
|
||||
|
@ -26,8 +25,10 @@ async def cmd(self, ctx):
|
|||
|
||||
else:
|
||||
emote = self.client.get_emoji(item.emote_id)
|
||||
embed.add_field(name=f"{emote} {item.display_name.capitalize()}",
|
||||
value=f"*— amount: `{quantity}`*",
|
||||
inline=False)
|
||||
embed.add_field(
|
||||
name=f"{emote} {item.display_name.capitalize()}",
|
||||
value=f"*— amount: `{quantity}`*",
|
||||
inline=False,
|
||||
)
|
||||
|
||||
await ctx.respond(embed=embed)
|
||||
|
|
|
@ -12,7 +12,7 @@ from services.currency_service import Currency
|
|||
from services.stats_service import SlotsStats
|
||||
|
||||
resources = JsonCache.read_json("resources")
|
||||
est = pytz.timezone('US/Eastern')
|
||||
est = pytz.timezone("US/Eastern")
|
||||
|
||||
|
||||
async def cmd(self, ctx, bet):
|
||||
|
@ -46,16 +46,26 @@ async def cmd(self, ctx, bet):
|
|||
emojis = get_emotes(self.client)
|
||||
|
||||
# start with default "spinning" embed
|
||||
await ctx.respond(embed=slots_spinning(ctx, 3, Currency.format_human(bet), results, emojis))
|
||||
await ctx.respond(
|
||||
embed=slots_spinning(ctx, 3, Currency.format_human(bet), results, emojis),
|
||||
)
|
||||
await asyncio.sleep(1)
|
||||
|
||||
for i in range(2, 0, -1):
|
||||
await ctx.edit(embed=slots_spinning(ctx, i, Currency.format_human(bet), results, emojis))
|
||||
await ctx.edit(
|
||||
embed=slots_spinning(ctx, i, Currency.format_human(bet), results, emojis),
|
||||
)
|
||||
await asyncio.sleep(1)
|
||||
|
||||
# output final result
|
||||
finished_output = slots_finished(ctx, type, Currency.format_human(bet),
|
||||
Currency.format_human(payout), results, emojis)
|
||||
finished_output = slots_finished(
|
||||
ctx,
|
||||
type,
|
||||
Currency.format_human(bet),
|
||||
Currency.format_human(payout),
|
||||
results,
|
||||
emojis,
|
||||
)
|
||||
|
||||
await ctx.edit(embed=finished_output)
|
||||
|
||||
|
@ -71,7 +81,7 @@ async def cmd(self, ctx, bet):
|
|||
bet=bet,
|
||||
payout=payout,
|
||||
spin_type=type,
|
||||
icons=results
|
||||
icons=results,
|
||||
)
|
||||
|
||||
ctx_currency.push()
|
||||
|
@ -104,7 +114,6 @@ def calculate_slots_results(bet, results):
|
|||
|
||||
# 3 of a kind
|
||||
elif len(counts) == 1:
|
||||
|
||||
if results[0] == 5:
|
||||
type = "three_diamonds"
|
||||
multiplier = rewards[type]
|
||||
|
@ -139,21 +148,25 @@ def slots_spinning(ctx, spinning_icons_amount, bet, results, emojis):
|
|||
one = first_slots_emote
|
||||
two = second_slots_emote
|
||||
|
||||
description = f"🎰{emojis['S_Wide']}{emojis['L_Wide']}{emojis['O_Wide']}{emojis['T_Wide']}{emojis['S_Wide']}🎰\n" \
|
||||
f"{emojis['CBorderTLeft']}{emojis['HBorderT']}{emojis['HBorderT']}{emojis['HBorderT']}" \
|
||||
f"{emojis['HBorderT']}{emojis['HBorderT']}{emojis['CBorderTRight']}\n" \
|
||||
f"{emojis['VBorder']}{one}{emojis['VBorder']}{two}{emojis['VBorder']}" \
|
||||
f"{three}{emojis['VBorder']}\n" \
|
||||
f"{emojis['CBorderBLeft']}{emojis['HBorderB']}{emojis['HBorderB']}{emojis['HBorderB']}" \
|
||||
f"{emojis['HBorderB']}{emojis['HBorderB']}{emojis['CBorderBRight']}\n" \
|
||||
f"{emojis['Blank']}{emojis['Blank']}❓❓❓{emojis['Blank']}{emojis['Blank']}{emojis['Blank']}"
|
||||
description = (
|
||||
f"🎰{emojis['S_Wide']}{emojis['L_Wide']}{emojis['O_Wide']}{emojis['T_Wide']}{emojis['S_Wide']}🎰\n"
|
||||
f"{emojis['CBorderTLeft']}{emojis['HBorderT']}{emojis['HBorderT']}{emojis['HBorderT']}"
|
||||
f"{emojis['HBorderT']}{emojis['HBorderT']}{emojis['CBorderTRight']}\n"
|
||||
f"{emojis['VBorder']}{one}{emojis['VBorder']}{two}{emojis['VBorder']}"
|
||||
f"{three}{emojis['VBorder']}\n"
|
||||
f"{emojis['CBorderBLeft']}{emojis['HBorderB']}{emojis['HBorderB']}{emojis['HBorderB']}"
|
||||
f"{emojis['HBorderB']}{emojis['HBorderB']}{emojis['CBorderBRight']}\n"
|
||||
f"{emojis['Blank']}{emojis['Blank']}❓❓❓{emojis['Blank']}{emojis['Blank']}{emojis['Blank']}"
|
||||
)
|
||||
|
||||
embed = discord.Embed(
|
||||
description=description
|
||||
description=description,
|
||||
)
|
||||
embed.set_author(name=ctx.author.name, icon_url=ctx.author.avatar.url)
|
||||
embed.set_footer(text=f"Bet ${bet} • jackpot = x15 • {current_time}",
|
||||
icon_url="https://i.imgur.com/wFsgSnr.png")
|
||||
embed.set_footer(
|
||||
text=f"Bet ${bet} • jackpot = x15 • {current_time}",
|
||||
icon_url="https://i.imgur.com/wFsgSnr.png",
|
||||
)
|
||||
|
||||
return embed
|
||||
|
||||
|
@ -190,27 +203,33 @@ def slots_finished(ctx, payout_type, bet, payout, results, emojis):
|
|||
is_lost = False
|
||||
color = discord.Color.green()
|
||||
|
||||
description = f"🎰{emojis['S_Wide']}{emojis['L_Wide']}{emojis['O_Wide']}{emojis['T_Wide']}{emojis['S_Wide']}🎰\n" \
|
||||
f"{emojis['CBorderTLeft']}{emojis['HBorderT']}{emojis['HBorderT']}{emojis['HBorderT']}" \
|
||||
f"{emojis['HBorderT']}{emojis['HBorderT']}{emojis['CBorderTRight']}\n" \
|
||||
f"{emojis['VBorder']}{first_slots_emote}{emojis['VBorder']}{second_slots_emote}" \
|
||||
f"{emojis['VBorder']}{third_slots_emote}{emojis['VBorder']}\n" \
|
||||
f"{emojis['CBorderBLeft']}{emojis['HBorderB']}{emojis['HBorderB']}{emojis['HBorderB']}" \
|
||||
f"{emojis['HBorderB']}{emojis['HBorderB']}{emojis['CBorderBRight']}"
|
||||
description = (
|
||||
f"🎰{emojis['S_Wide']}{emojis['L_Wide']}{emojis['O_Wide']}{emojis['T_Wide']}{emojis['S_Wide']}🎰\n"
|
||||
f"{emojis['CBorderTLeft']}{emojis['HBorderT']}{emojis['HBorderT']}{emojis['HBorderT']}"
|
||||
f"{emojis['HBorderT']}{emojis['HBorderT']}{emojis['CBorderTRight']}\n"
|
||||
f"{emojis['VBorder']}{first_slots_emote}{emojis['VBorder']}{second_slots_emote}"
|
||||
f"{emojis['VBorder']}{third_slots_emote}{emojis['VBorder']}\n"
|
||||
f"{emojis['CBorderBLeft']}{emojis['HBorderB']}{emojis['HBorderB']}{emojis['HBorderB']}"
|
||||
f"{emojis['HBorderB']}{emojis['HBorderB']}{emojis['CBorderBRight']}"
|
||||
)
|
||||
|
||||
if is_lost:
|
||||
description += f"\n{emojis['Blank']}{emojis['LCentered']}{emojis['OCentered']}{emojis['SCentered']}" \
|
||||
f"{emojis['ECentered']}{emojis['lost']}{emojis['Blank']}"
|
||||
description += (
|
||||
f"\n{emojis['Blank']}{emojis['LCentered']}{emojis['OCentered']}{emojis['SCentered']}"
|
||||
f"{emojis['ECentered']}{emojis['lost']}{emojis['Blank']}"
|
||||
)
|
||||
else:
|
||||
description += f"\n{emojis['Blank']}🎉{emojis['WSmall']}{emojis['ISmall']}{emojis['NSmall']}🎉{emojis['Blank']}"
|
||||
|
||||
embed = discord.Embed(
|
||||
color=color,
|
||||
description=description
|
||||
description=description,
|
||||
)
|
||||
embed.add_field(name=field_name, value=field_value, inline=False)
|
||||
embed.set_author(name=ctx.author.name, icon_url=ctx.author.avatar.url)
|
||||
embed.set_footer(text=f"Game finished • {current_time}",
|
||||
icon_url="https://i.imgur.com/wFsgSnr.png")
|
||||
embed.set_footer(
|
||||
text=f"Game finished • {current_time}",
|
||||
icon_url="https://i.imgur.com/wFsgSnr.png",
|
||||
)
|
||||
|
||||
return embed
|
||||
|
|
|
@ -21,7 +21,7 @@ async def cmd(self, ctx, game):
|
|||
stats["amount_of_games"],
|
||||
total_bet,
|
||||
stats["winning_amount"],
|
||||
total_payout
|
||||
total_payout,
|
||||
)
|
||||
|
||||
elif game == "Slots":
|
||||
|
@ -31,12 +31,18 @@ async def cmd(self, ctx, game):
|
|||
total_bet = Currency.format_human(stats["total_bet"])
|
||||
total_payout = Currency.format_human(stats["total_payout"])
|
||||
|
||||
output = strings["stats_slots"].format(stats["amount_of_games"], total_bet, total_payout)
|
||||
output = strings["stats_slots"].format(
|
||||
stats["amount_of_games"],
|
||||
total_bet,
|
||||
total_payout,
|
||||
)
|
||||
output += "\n\n"
|
||||
|
||||
pair_emote = self.client.get_emoji(resources["slots"]["emotes"]["slots_0_id"])
|
||||
three_emote = self.client.get_emoji(resources["slots"]["emotes"]["slots_4_id"])
|
||||
diamonds_emote = self.client.get_emoji(resources["slots"]["emotes"]["slots_5_id"])
|
||||
diamonds_emote = self.client.get_emoji(
|
||||
resources["slots"]["emotes"]["slots_5_id"],
|
||||
)
|
||||
seven_emote = self.client.get_emoji(resources["slots"]["emotes"]["slots_6_id"])
|
||||
|
||||
output += f"{pair_emote} | **{stats['games_won_pair']}** pairs.\n"
|
||||
|
|
|
@ -131,7 +131,8 @@ class LeaderboardCommandView(discord.ui.View):
|
|||
embed.set_author(name=CONST.STRINGS["xp_lb_author"], icon_url=icon)
|
||||
|
||||
for rank, (user_id, xp, level, xp_needed_for_next_level) in enumerate(
|
||||
xp_lb[:5], start=1
|
||||
xp_lb[:5],
|
||||
start=1,
|
||||
):
|
||||
try:
|
||||
member = await self.ctx.guild.fetch_member(user_id)
|
||||
|
@ -141,7 +142,9 @@ class LeaderboardCommandView(discord.ui.View):
|
|||
embed.add_field(
|
||||
name=CONST.STRINGS["xp_lb_field_name"].format(rank, member.name),
|
||||
value=CONST.STRINGS["xp_lb_field_value"].format(
|
||||
level, xp, xp_needed_for_next_level
|
||||
level,
|
||||
xp,
|
||||
xp_needed_for_next_level,
|
||||
),
|
||||
inline=False,
|
||||
)
|
||||
|
@ -165,7 +168,7 @@ class LeaderboardCommandView(discord.ui.View):
|
|||
embed.add_field(
|
||||
name=f"#{rank} - {name}",
|
||||
value=CONST.STRINGS["xp_lb_currency_field_value"].format(
|
||||
Currency.format(balance)
|
||||
Currency.format(balance),
|
||||
),
|
||||
inline=False,
|
||||
)
|
||||
|
@ -191,7 +194,8 @@ class LeaderboardCommandView(discord.ui.View):
|
|||
embed.add_field(
|
||||
name=f"#{rank} - {name}",
|
||||
value=CONST.STRINGS["xp_lb_dailies_field_value"].format(
|
||||
streak, claimed_at
|
||||
streak,
|
||||
claimed_at,
|
||||
),
|
||||
inline=False,
|
||||
)
|
||||
|
|
|
@ -98,7 +98,9 @@ class Misc(commands.Cog):
|
|||
xkcd submodule - slash command only
|
||||
"""
|
||||
xkcd: SlashCommandGroup = SlashCommandGroup(
|
||||
"xkcd", "A web comic of romance, sarcasm, math, and language.", guild_only=False
|
||||
"xkcd",
|
||||
"A web comic of romance, sarcasm, math, and language.",
|
||||
guild_only=False,
|
||||
)
|
||||
|
||||
@xkcd.command(name="latest", description="Get the latest xkcd comic.")
|
||||
|
|
|
@ -18,8 +18,10 @@ async def get_avatar(ctx: bridge.Context, member: Member) -> None:
|
|||
The discord context object.
|
||||
member : Member
|
||||
The member to get the avatar of.
|
||||
"""
|
||||
guild_avatar: Optional[str] = member.guild_avatar.url if member.guild_avatar else None
|
||||
"""
|
||||
guild_avatar: Optional[str] = (
|
||||
member.guild_avatar.url if member.guild_avatar else None
|
||||
)
|
||||
profile_avatar: Optional[str] = member.avatar.url if member.avatar else None
|
||||
|
||||
files: list[File] = [
|
||||
|
|
|
@ -16,14 +16,16 @@ async def cmd(self, ctx: bridge.Context, unix_timestamp: int) -> None:
|
|||
memory_usage_in_mb: float = psutil.Process().memory_info().rss / (1024 * 1024)
|
||||
total_rows: str = Currency.format(BlackJackStats.get_total_rows_count())
|
||||
|
||||
description: str = "".join([
|
||||
CONST.STRINGS["info_uptime"].format(unix_timestamp),
|
||||
CONST.STRINGS["info_latency"].format(round(1000 * self.client.latency)),
|
||||
CONST.STRINGS["info_memory"].format(memory_usage_in_mb),
|
||||
CONST.STRINGS["info_system"].format(platform.system(), os.name),
|
||||
CONST.STRINGS["info_api_version"].format(discord.__version__),
|
||||
CONST.STRINGS["info_database_records"].format(total_rows)
|
||||
])
|
||||
description: str = "".join(
|
||||
[
|
||||
CONST.STRINGS["info_uptime"].format(unix_timestamp),
|
||||
CONST.STRINGS["info_latency"].format(round(1000 * self.client.latency)),
|
||||
CONST.STRINGS["info_memory"].format(memory_usage_in_mb),
|
||||
CONST.STRINGS["info_system"].format(platform.system(), os.name),
|
||||
CONST.STRINGS["info_api_version"].format(discord.__version__),
|
||||
CONST.STRINGS["info_database_records"].format(total_rows),
|
||||
],
|
||||
)
|
||||
|
||||
embed: discord.Embed = EmbedBuilder.create_success_embed(
|
||||
ctx,
|
||||
|
|
|
@ -25,17 +25,18 @@ async def cmd(self, ctx: bridge.Context) -> None:
|
|||
author_text=CONST.STRINGS["intro_no_guild_author"],
|
||||
description=CONST.STRINGS["intro_no_guild"],
|
||||
footer_text=CONST.STRINGS["intro_service_name"],
|
||||
)
|
||||
),
|
||||
)
|
||||
return
|
||||
|
||||
question_mapping: Dict[str, str] = CONST.KRC_QUESTION_MAPPING
|
||||
channel: Optional[discord.abc.GuildChannel] = guild.get_channel(
|
||||
CONST.KRC_INTRO_CHANNEL_ID
|
||||
CONST.KRC_INTRO_CHANNEL_ID,
|
||||
)
|
||||
|
||||
if not channel or isinstance(
|
||||
channel, (discord.ForumChannel, discord.CategoryChannel)
|
||||
channel,
|
||||
(discord.ForumChannel, discord.CategoryChannel),
|
||||
):
|
||||
await ctx.respond(
|
||||
embed=EmbedBuilder.create_error_embed(
|
||||
|
@ -43,7 +44,7 @@ async def cmd(self, ctx: bridge.Context) -> None:
|
|||
author_text=CONST.STRINGS["intro_no_channel_author"],
|
||||
description=CONST.STRINGS["intro_no_channel"],
|
||||
footer_text=CONST.STRINGS["intro_service_name"],
|
||||
)
|
||||
),
|
||||
)
|
||||
return
|
||||
|
||||
|
@ -68,7 +69,7 @@ async def cmd(self, ctx: bridge.Context) -> None:
|
|||
author_text=CONST.STRINGS["intro_stopped_author"],
|
||||
description=CONST.STRINGS["intro_stopped"],
|
||||
footer_text=CONST.STRINGS["intro_service_name"],
|
||||
)
|
||||
),
|
||||
)
|
||||
return
|
||||
|
||||
|
@ -76,7 +77,8 @@ async def cmd(self, ctx: bridge.Context) -> None:
|
|||
|
||||
def check(message: discord.Message) -> bool:
|
||||
return message.author == ctx.author and isinstance(
|
||||
message.channel, discord.DMChannel
|
||||
message.channel,
|
||||
discord.DMChannel,
|
||||
)
|
||||
|
||||
answer_mapping: Dict[str, str] = {}
|
||||
|
@ -88,12 +90,14 @@ async def cmd(self, ctx: bridge.Context) -> None:
|
|||
author_text=key,
|
||||
description=question,
|
||||
footer_text=CONST.STRINGS["intro_question_footer"],
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
try:
|
||||
answer: discord.Message = await self.client.wait_for(
|
||||
"message", check=check, timeout=120
|
||||
"message",
|
||||
check=check,
|
||||
timeout=120,
|
||||
)
|
||||
answer_content: str = answer.content.replace("\n", " ")
|
||||
|
||||
|
@ -104,7 +108,7 @@ async def cmd(self, ctx: bridge.Context) -> None:
|
|||
author_text=CONST.STRINGS["intro_too_long_author"],
|
||||
description=CONST.STRINGS["intro_too_long"],
|
||||
footer_text=CONST.STRINGS["intro_service_name"],
|
||||
)
|
||||
),
|
||||
)
|
||||
return
|
||||
|
||||
|
@ -117,7 +121,7 @@ async def cmd(self, ctx: bridge.Context) -> None:
|
|||
author_text=CONST.STRINGS["intro_timeout_author"],
|
||||
description=CONST.STRINGS["intro_timeout"],
|
||||
footer_text=CONST.STRINGS["intro_service_name"],
|
||||
)
|
||||
),
|
||||
)
|
||||
return
|
||||
|
||||
|
@ -147,9 +151,9 @@ async def cmd(self, ctx: bridge.Context) -> None:
|
|||
embed=EmbedBuilder.create_embed(
|
||||
ctx,
|
||||
description=CONST.STRINGS["intro_post_confirmation"].format(
|
||||
channel.mention
|
||||
channel.mention,
|
||||
),
|
||||
)
|
||||
),
|
||||
)
|
||||
else:
|
||||
await ctx.send(
|
||||
|
@ -158,5 +162,5 @@ async def cmd(self, ctx: bridge.Context) -> None:
|
|||
author_text=CONST.STRINGS["intro_stopped_author"],
|
||||
description=CONST.STRINGS["intro_stopped"],
|
||||
footer_text=CONST.STRINGS["intro_service_name"],
|
||||
)
|
||||
),
|
||||
)
|
||||
|
|
|
@ -9,7 +9,8 @@ from lib.constants import CONST
|
|||
async def cmd(ctx: bridge.BridgeContext) -> None:
|
||||
await ctx.respond(
|
||||
embed=EmbedBuilder.create_success_embed(
|
||||
ctx, description=CONST.STRINGS["invite_description"]
|
||||
ctx,
|
||||
description=CONST.STRINGS["invite_description"],
|
||||
),
|
||||
view=InviteButton(),
|
||||
)
|
||||
|
|
|
@ -3,22 +3,28 @@ from lib.embed_builder import EmbedBuilder
|
|||
from lib.constants import CONST
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
async def ping(self, ctx: bridge.BridgeContext) -> None:
|
||||
embed = EmbedBuilder.create_success_embed(
|
||||
ctx,
|
||||
author_text=CONST.STRINGS["ping_author"],
|
||||
description=CONST.STRINGS["ping_pong"],
|
||||
footer_text=CONST.STRINGS["ping_footer"].format(round(1000 * self.client.latency))
|
||||
footer_text=CONST.STRINGS["ping_footer"].format(
|
||||
round(1000 * self.client.latency),
|
||||
),
|
||||
)
|
||||
await ctx.respond(embed=embed)
|
||||
|
||||
|
||||
async def uptime(self, ctx: bridge.BridgeContext, start_time: datetime) -> None:
|
||||
unix_timestamp: int = int(round(self.start_time.timestamp()))
|
||||
|
||||
|
||||
embed = EmbedBuilder.create_success_embed(
|
||||
ctx,
|
||||
author_text=CONST.STRINGS["ping_author"],
|
||||
description=CONST.STRINGS["ping_uptime"].format(unix_timestamp),
|
||||
footer_text=CONST.STRINGS["ping_footer"].format(round(1000 * self.client.latency))
|
||||
footer_text=CONST.STRINGS["ping_footer"].format(
|
||||
round(1000 * self.client.latency),
|
||||
),
|
||||
)
|
||||
await ctx.respond(embed=embed)
|
||||
|
|
|
@ -7,7 +7,11 @@ from typing import Optional
|
|||
_xkcd = Client()
|
||||
|
||||
|
||||
async def print_comic(ctx: bridge.Context, latest: bool = False, number: Optional[int] = None) -> None:
|
||||
async def print_comic(
|
||||
ctx: bridge.Context,
|
||||
latest: bool = False,
|
||||
number: Optional[int] = None,
|
||||
) -> None:
|
||||
try:
|
||||
if latest:
|
||||
comic = _xkcd.get_latest_comic(raw_comic_image=True)
|
||||
|
@ -20,11 +24,14 @@ async def print_comic(ctx: bridge.Context, latest: bool = False, number: Optiona
|
|||
embed=EmbedBuilder.create_success_embed(
|
||||
ctx,
|
||||
author_text=CONST.STRINGS["xkcd_title"].format(comic.id, comic.title),
|
||||
description=CONST.STRINGS["xkcd_description"].format(comic.explanation_url, comic.comic_url),
|
||||
description=CONST.STRINGS["xkcd_description"].format(
|
||||
comic.explanation_url,
|
||||
comic.comic_url,
|
||||
),
|
||||
footer_text=CONST.STRINGS["xkcd_footer"],
|
||||
image_url=comic.image_url,
|
||||
show_name=False,
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
except HttpError:
|
||||
|
@ -34,5 +41,5 @@ async def print_comic(ctx: bridge.Context, latest: bool = False, number: Optiona
|
|||
author_text=CONST.STRINGS["xkcd_not_found_author"],
|
||||
description=CONST.STRINGS["xkcd_not_found"],
|
||||
footer_text=CONST.STRINGS["xkcd_footer"],
|
||||
)
|
||||
),
|
||||
)
|
||||
|
|
|
@ -5,7 +5,6 @@ from modules.moderation import ban
|
|||
|
||||
|
||||
class Moderation(commands.Cog):
|
||||
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
|
||||
|
@ -14,12 +13,18 @@ class Moderation(commands.Cog):
|
|||
aliases=["b"],
|
||||
description="Ban a user from the server.",
|
||||
help="Bans a user from the server, you can use ID or mention them.",
|
||||
guild_only=True
|
||||
guild_only=True,
|
||||
)
|
||||
@bridge.has_permissions(ban_members=True)
|
||||
@commands.bot_has_permissions(ban_members=True)
|
||||
@commands.guild_only()
|
||||
async def ban_command(self, ctx, target: discord.User, *, reason: str | None = None):
|
||||
async def ban_command(
|
||||
self,
|
||||
ctx,
|
||||
target: discord.User,
|
||||
*,
|
||||
reason: str | None = None,
|
||||
):
|
||||
await ban.ban_user(self, ctx, target, reason)
|
||||
|
||||
@bridge.bridge_command(
|
||||
|
@ -27,12 +32,18 @@ class Moderation(commands.Cog):
|
|||
aliases=["ub", "pardon"],
|
||||
description="Unbans a user from the server.",
|
||||
help="Unbans a user from the server, you can use ID or provide their username.",
|
||||
guild_only=True
|
||||
guild_only=True,
|
||||
)
|
||||
@bridge.has_permissions(ban_members=True)
|
||||
@commands.bot_has_permissions(ban_members=True)
|
||||
@commands.guild_only()
|
||||
async def unban_command(self, ctx, target: discord.User, *, reason: str | None = None):
|
||||
async def unban_command(
|
||||
self,
|
||||
ctx,
|
||||
target: discord.User,
|
||||
*,
|
||||
reason: str | None = None,
|
||||
):
|
||||
await ban.unban_user(ctx, target, reason)
|
||||
|
||||
|
||||
|
|
|
@ -24,10 +24,12 @@ async def ban_user(cog, ctx, target: discord.User, reason):
|
|||
ctx,
|
||||
author_text=CONST.STRINGS["mod_banned_author"],
|
||||
description=CONST.STRINGS["mod_ban_dm"].format(
|
||||
target.name, ctx.guild.name, reason
|
||||
target.name,
|
||||
ctx.guild.name,
|
||||
reason,
|
||||
),
|
||||
show_name=False,
|
||||
)
|
||||
),
|
||||
)
|
||||
dm_sent = True
|
||||
|
||||
|
@ -36,8 +38,9 @@ async def ban_user(cog, ctx, target: discord.User, reason):
|
|||
|
||||
await member.ban(
|
||||
reason=CONST.STRINGS["mod_reason"].format(
|
||||
ctx.author.name, formatter.shorten(reason, 200)
|
||||
)
|
||||
ctx.author.name,
|
||||
formatter.shorten(reason, 200),
|
||||
),
|
||||
)
|
||||
return await ctx.respond(
|
||||
embed=EmbedBuilder.create_success_embed(
|
||||
|
@ -47,7 +50,7 @@ async def ban_user(cog, ctx, target: discord.User, reason):
|
|||
footer_text=CONST.STRINGS["mod_dm_sent"]
|
||||
if dm_sent
|
||||
else CONST.STRINGS["mod_dm_not_sent"],
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
# not a member in this guild, so ban right away
|
||||
|
@ -55,7 +58,8 @@ async def ban_user(cog, ctx, target: discord.User, reason):
|
|||
await ctx.guild.ban(
|
||||
target,
|
||||
reason=CONST.STRINGS["mod_reason"].format(
|
||||
ctx.author.name, formatter.shorten(reason, 200)
|
||||
ctx.author.name,
|
||||
formatter.shorten(reason, 200),
|
||||
),
|
||||
)
|
||||
return await ctx.respond(
|
||||
|
@ -63,7 +67,7 @@ async def ban_user(cog, ctx, target: discord.User, reason):
|
|||
ctx,
|
||||
author_text=CONST.STRINGS["mod_banned_author"],
|
||||
description=CONST.STRINGS["mod_banned_user"].format(target.id),
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
|
@ -75,7 +79,8 @@ async def unban_user(ctx, target: discord.User, reason):
|
|||
await ctx.guild.unban(
|
||||
target,
|
||||
reason=CONST.STRINGS["mod_reason"].format(
|
||||
ctx.author.name, formatter.shorten(reason, 200)
|
||||
ctx.author.name,
|
||||
formatter.shorten(reason, 200),
|
||||
),
|
||||
)
|
||||
return await ctx.respond(
|
||||
|
@ -83,7 +88,7 @@ async def unban_user(ctx, target: discord.User, reason):
|
|||
ctx,
|
||||
author_text=CONST.STRINGS["mod_unbanned_author"],
|
||||
description=CONST.STRINGS["mod_unbanned"].format(target.id),
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
except (discord.NotFound, discord.HTTPException):
|
||||
|
@ -92,5 +97,5 @@ async def unban_user(ctx, target: discord.User, reason):
|
|||
ctx,
|
||||
author_text=CONST.STRINGS["mod_not_banned_author"],
|
||||
description=CONST.STRINGS["mod_not_banned"].format(target.id),
|
||||
)
|
||||
),
|
||||
)
|
||||
|
|
|
@ -4,7 +4,11 @@ from discord.ext.commands import BadArgument
|
|||
from lib.exceptions import LumiExceptions
|
||||
|
||||
|
||||
def actionable(target: discord.Member, invoker: discord.Member, bot_user: discord.Member) -> None:
|
||||
def actionable(
|
||||
target: discord.Member,
|
||||
invoker: discord.Member,
|
||||
bot_user: discord.Member,
|
||||
) -> None:
|
||||
"""
|
||||
Checks if the invoker and client have a higher role than the target user.
|
||||
|
||||
|
|
|
@ -13,7 +13,10 @@ class Triggers(commands.Cog):
|
|||
self.client = client
|
||||
|
||||
trigger = SlashCommandGroup(
|
||||
"trigger", "Manage custom reactions.", guild_only=True, default_member_permissions=discord.Permissions(manage_guild=True)
|
||||
"trigger",
|
||||
"Manage custom reactions.",
|
||||
guild_only=True,
|
||||
default_member_permissions=discord.Permissions(manage_guild=True),
|
||||
)
|
||||
add = trigger.create_subgroup("add", "Add new custom reactions.")
|
||||
|
||||
|
@ -28,7 +31,7 @@ class Triggers(commands.Cog):
|
|||
ctx,
|
||||
trigger_text: str,
|
||||
response: str,
|
||||
is_full_match: bool
|
||||
is_full_match: bool,
|
||||
):
|
||||
await add_reaction(ctx, trigger_text, response, None, False, is_full_match)
|
||||
|
||||
|
@ -43,10 +46,10 @@ class Triggers(commands.Cog):
|
|||
ctx,
|
||||
trigger_text: str,
|
||||
emoji: discord.Emoji,
|
||||
is_full_match: bool
|
||||
is_full_match: bool,
|
||||
):
|
||||
await add_reaction(ctx, trigger_text, None, emoji.id, True, is_full_match)
|
||||
|
||||
|
||||
@trigger.command(
|
||||
name="delete",
|
||||
description="Delete an existing custom reaction.",
|
||||
|
@ -56,10 +59,10 @@ class Triggers(commands.Cog):
|
|||
async def delete_reaction_command(
|
||||
self,
|
||||
ctx,
|
||||
reaction_id: int
|
||||
reaction_id: int,
|
||||
):
|
||||
await delete_reaction(ctx, reaction_id)
|
||||
|
||||
|
||||
@trigger.command(
|
||||
name="list",
|
||||
description="List all custom reactions.",
|
||||
|
@ -68,9 +71,10 @@ class Triggers(commands.Cog):
|
|||
@commands.guild_only()
|
||||
async def list_reactions_command(
|
||||
self,
|
||||
ctx
|
||||
ctx,
|
||||
):
|
||||
await list_reactions(ctx)
|
||||
|
||||
|
||||
def setup(client: LumiBot):
|
||||
client.add_cog(Triggers(client))
|
||||
client.add_cog(Triggers(client))
|
||||
|
|
|
@ -3,18 +3,38 @@ from typing import Optional
|
|||
from services.reactions_service import CustomReactionsService
|
||||
from lib.embeds.triggers import create_creation_embed, create_failure_embed
|
||||
|
||||
async def add_reaction(ctx: bridge.Context, trigger_text: str, response: Optional[str], emoji_id: Optional[int], is_emoji: bool, is_full_match: bool) -> None:
|
||||
|
||||
async def add_reaction(
|
||||
ctx: bridge.Context,
|
||||
trigger_text: str,
|
||||
response: Optional[str],
|
||||
emoji_id: Optional[int],
|
||||
is_emoji: bool,
|
||||
is_full_match: bool,
|
||||
) -> None:
|
||||
if ctx.guild is None:
|
||||
return
|
||||
|
||||
|
||||
reaction_service = CustomReactionsService()
|
||||
guild_id: int = ctx.guild.id
|
||||
creator_id: int = ctx.author.id
|
||||
|
||||
if not await check_reaction_limit(ctx, reaction_service, guild_id, trigger_text, is_emoji):
|
||||
if not await check_reaction_limit(
|
||||
ctx,
|
||||
reaction_service,
|
||||
guild_id,
|
||||
trigger_text,
|
||||
is_emoji,
|
||||
):
|
||||
return
|
||||
|
||||
if not await check_existing_trigger(ctx, reaction_service, guild_id, trigger_text, is_emoji):
|
||||
if not await check_existing_trigger(
|
||||
ctx,
|
||||
reaction_service,
|
||||
guild_id,
|
||||
trigger_text,
|
||||
is_emoji,
|
||||
):
|
||||
return
|
||||
|
||||
success: bool = await reaction_service.create_custom_reaction(
|
||||
|
@ -25,27 +45,51 @@ async def add_reaction(ctx: bridge.Context, trigger_text: str, response: Optiona
|
|||
emoji_id=emoji_id,
|
||||
is_emoji=is_emoji,
|
||||
is_full_match=is_full_match,
|
||||
is_global=False, # only bot admins can create global custom reactions
|
||||
is_global=False, # only bot admins can create global custom reactions
|
||||
)
|
||||
|
||||
if success:
|
||||
embed = create_creation_embed(trigger_text, response, emoji_id, is_emoji, is_full_match)
|
||||
embed = create_creation_embed(
|
||||
trigger_text,
|
||||
response,
|
||||
emoji_id,
|
||||
is_emoji,
|
||||
is_full_match,
|
||||
)
|
||||
await ctx.respond(embed=embed)
|
||||
else:
|
||||
embed = create_failure_embed(trigger_text, is_emoji)
|
||||
await ctx.respond(embed=embed)
|
||||
|
||||
async def check_reaction_limit(ctx: bridge.Context, reaction_service: CustomReactionsService, guild_id: int, trigger_text: str, is_emoji: bool) -> bool:
|
||||
|
||||
async def check_reaction_limit(
|
||||
ctx: bridge.Context,
|
||||
reaction_service: CustomReactionsService,
|
||||
guild_id: int,
|
||||
trigger_text: str,
|
||||
is_emoji: bool,
|
||||
) -> bool:
|
||||
if await reaction_service.count_custom_reactions(guild_id) >= 100:
|
||||
embed = create_failure_embed(trigger_text, is_emoji, limit_reached=True)
|
||||
await ctx.respond(embed=embed)
|
||||
return False
|
||||
return True
|
||||
|
||||
async def check_existing_trigger(ctx: bridge.Context, reaction_service: CustomReactionsService, guild_id: int, trigger_text: str, is_emoji: bool) -> bool:
|
||||
|
||||
async def check_existing_trigger(
|
||||
ctx: bridge.Context,
|
||||
reaction_service: CustomReactionsService,
|
||||
guild_id: int,
|
||||
trigger_text: str,
|
||||
is_emoji: bool,
|
||||
) -> bool:
|
||||
existing_trigger = await reaction_service.find_trigger(guild_id, trigger_text)
|
||||
if existing_trigger:
|
||||
embed = create_failure_embed(trigger_text, is_emoji, trigger_already_exists=True)
|
||||
embed = create_failure_embed(
|
||||
trigger_text,
|
||||
is_emoji,
|
||||
trigger_already_exists=True,
|
||||
)
|
||||
await ctx.respond(embed=embed)
|
||||
return False
|
||||
return True
|
||||
return True
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
from discord.ext import bridge
|
||||
from services.reactions_service import CustomReactionsService
|
||||
from lib.embeds.triggers import create_deletion_embed, create_failure_embed, create_not_found_embed
|
||||
from lib.embeds.triggers import (
|
||||
create_deletion_embed,
|
||||
create_failure_embed,
|
||||
create_not_found_embed,
|
||||
)
|
||||
|
||||
|
||||
async def delete_reaction(ctx: bridge.Context, reaction_id: int) -> None:
|
||||
if ctx.guild is None:
|
||||
return
|
||||
|
||||
|
||||
reaction_service = CustomReactionsService()
|
||||
guild_id: int = ctx.guild.id
|
||||
|
||||
|
@ -27,4 +32,4 @@ async def delete_reaction(ctx: bridge.Context, reaction_id: int) -> None:
|
|||
await ctx.respond(embed=embed)
|
||||
else:
|
||||
embed = create_failure_embed(trigger_text, is_emoji)
|
||||
await ctx.respond(embed=embed)
|
||||
await ctx.respond(embed=embed)
|
||||
|
|
|
@ -10,10 +10,11 @@ resources = JsonCache.read_json("art")
|
|||
check_icon = resources["icons"]["check"]
|
||||
logo = resources["logo"]["transparent"]
|
||||
|
||||
|
||||
async def list_reactions(ctx: bridge.Context) -> None:
|
||||
if ctx.guild is None:
|
||||
return
|
||||
|
||||
|
||||
reaction_service = CustomReactionsService()
|
||||
guild_id: int = ctx.guild.id
|
||||
|
||||
|
@ -37,7 +38,7 @@ async def list_reactions(ctx: bridge.Context) -> None:
|
|||
embed = discord.Embed(
|
||||
title=f"ID: {reaction['id']}",
|
||||
description=description,
|
||||
color=0xFF8C00
|
||||
color=0xFF8C00,
|
||||
)
|
||||
embed.set_author(name="Custom Reactions", icon_url=check_icon)
|
||||
embed.set_footer(text="Reaction Service", icon_url=logo)
|
||||
|
|
6
poetry.lock
generated
6
poetry.lock
generated
|
@ -755,13 +755,13 @@ voice = ["PyNaCl (>=1.3.0,<1.6)"]
|
|||
|
||||
[[package]]
|
||||
name = "pyright"
|
||||
version = "1.1.371"
|
||||
version = "1.1.372"
|
||||
description = "Command line wrapper for pyright"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "pyright-1.1.371-py3-none-any.whl", hash = "sha256:cce52e42ff73943243e7e5e24f2a59dee81b97d99f4e3cf97370b27e8a1858cd"},
|
||||
{file = "pyright-1.1.371.tar.gz", hash = "sha256:777b508b92dda2db476214c400ce043aad8d8f3dd0e10d284c96e79f298308b5"},
|
||||
{file = "pyright-1.1.372-py3-none-any.whl", hash = "sha256:25b15fb8967740f0949fd35b963777187f0a0404c0bd753cc966ec139f3eaa0b"},
|
||||
{file = "pyright-1.1.372.tar.gz", hash = "sha256:a9f5e0daa955daaa17e3d1ef76d3623e75f8afd5e37b437d3ff84d5b38c15420"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
|
|
@ -38,4 +38,3 @@ class BlacklistUserService:
|
|||
"""
|
||||
result: List[Tuple[bool]] = database.select_query(query, (user_id,))
|
||||
return any(active for (active,) in result)
|
||||
|
||||
|
|
|
@ -31,10 +31,19 @@ class GuildConfig:
|
|||
"""
|
||||
|
||||
try:
|
||||
(birthday_channel_id, command_channel_id, intro_channel_id,
|
||||
welcome_channel_id, welcome_message, boost_channel_id, boost_message, boost_image_url,
|
||||
level_channel_id, level_message, level_message_type) = \
|
||||
database.select_query(query, (self.guild_id,))[0]
|
||||
(
|
||||
birthday_channel_id,
|
||||
command_channel_id,
|
||||
intro_channel_id,
|
||||
welcome_channel_id,
|
||||
welcome_message,
|
||||
boost_channel_id,
|
||||
boost_message,
|
||||
boost_image_url,
|
||||
level_channel_id,
|
||||
level_message,
|
||||
level_message_type,
|
||||
) = database.select_query(query, (self.guild_id,))[0]
|
||||
|
||||
self.birthday_channel_id = birthday_channel_id
|
||||
self.command_channel_id = command_channel_id
|
||||
|
@ -71,11 +80,23 @@ class GuildConfig:
|
|||
WHERE guild_id = %s;
|
||||
"""
|
||||
|
||||
database.execute_query(query, (self.birthday_channel_id, self.command_channel_id,
|
||||
self.intro_channel_id, self.welcome_channel_id, self.welcome_message,
|
||||
self.boost_channel_id, self.boost_message, self.boost_image_url,
|
||||
self.level_channel_id, self.level_message,
|
||||
self.level_message_type, self.guild_id))
|
||||
database.execute_query(
|
||||
query,
|
||||
(
|
||||
self.birthday_channel_id,
|
||||
self.command_channel_id,
|
||||
self.intro_channel_id,
|
||||
self.welcome_channel_id,
|
||||
self.welcome_message,
|
||||
self.boost_channel_id,
|
||||
self.boost_message,
|
||||
self.boost_image_url,
|
||||
self.level_channel_id,
|
||||
self.level_message,
|
||||
self.level_message_type,
|
||||
self.guild_id,
|
||||
),
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_prefix(guild_id):
|
||||
|
|
|
@ -74,14 +74,18 @@ class Currency:
|
|||
|
||||
@staticmethod
|
||||
def format_human(num):
|
||||
num = float('{:.3g}'.format(num))
|
||||
num = float("{:.3g}".format(num))
|
||||
magnitude = 0
|
||||
while abs(num) >= 1000:
|
||||
magnitude += 1
|
||||
num /= 1000.0
|
||||
|
||||
return '{}{}'.format('{:f}'.format(num).rstrip('0').rstrip('.'),
|
||||
['', 'K', 'M', 'B', 'T', 'Q', 'Qi', 'Sx', 'Sp', 'Oc', 'No', 'Dc'][magnitude])
|
||||
return "{}{}".format(
|
||||
"{:f}".format(num).rstrip("0").rstrip("."),
|
||||
["", "K", "M", "B", "T", "Q", "Qi", "Sx", "Sp", "Oc", "No", "Dc"][
|
||||
magnitude
|
||||
],
|
||||
)
|
||||
|
||||
# A Thousand = K
|
||||
# Million = M
|
||||
|
|
|
@ -17,7 +17,10 @@ class Dailies:
|
|||
self.tz = pytz.timezone("US/Eastern")
|
||||
self.time_now: datetime = datetime.now(tz=self.tz)
|
||||
self.reset_time: datetime = self.time_now.replace(
|
||||
hour=7, minute=0, second=0, microsecond=0
|
||||
hour=7,
|
||||
minute=0,
|
||||
second=0,
|
||||
microsecond=0,
|
||||
)
|
||||
|
||||
data: Tuple[Optional[str], int] = Dailies.get_data(user_id)
|
||||
|
|
|
@ -76,16 +76,18 @@ class LumiHelp(commands.HelpCommand):
|
|||
channel = self.get_destination()
|
||||
await channel.send(
|
||||
embed=HelpErrors.error_message(
|
||||
self.context, f'No command called "{group.qualified_name}" found.'
|
||||
)
|
||||
self.context,
|
||||
f'No command called "{group.qualified_name}" found.',
|
||||
),
|
||||
)
|
||||
|
||||
async def send_cog_help(self, cog):
|
||||
channel = self.get_destination()
|
||||
await channel.send(
|
||||
embed=HelpErrors.error_message(
|
||||
self.context, f'No command called "{cog.qualified_name}" found.'
|
||||
)
|
||||
self.context,
|
||||
f'No command called "{cog.qualified_name}" found.',
|
||||
),
|
||||
)
|
||||
|
||||
async def command_callback(self, ctx, *, command=None):
|
||||
|
@ -112,7 +114,8 @@ class LumiHelp(commands.HelpCommand):
|
|||
cmd = bot.all_commands.get(keys[0].removeprefix(self.context.prefix))
|
||||
if cmd is None:
|
||||
string = await maybe_coro(
|
||||
self.command_not_found, self.remove_mentions(keys[0])
|
||||
self.command_not_found,
|
||||
self.remove_mentions(keys[0]),
|
||||
)
|
||||
return await self.send_error_message(string)
|
||||
|
||||
|
@ -121,13 +124,17 @@ class LumiHelp(commands.HelpCommand):
|
|||
found = cmd.all_commands.get(key)
|
||||
except AttributeError:
|
||||
string = await maybe_coro(
|
||||
self.subcommand_not_found, cmd, self.remove_mentions(key)
|
||||
self.subcommand_not_found,
|
||||
cmd,
|
||||
self.remove_mentions(key),
|
||||
)
|
||||
return await self.send_error_message(string)
|
||||
else:
|
||||
if found is None:
|
||||
string = await maybe_coro(
|
||||
self.subcommand_not_found, cmd, self.remove_mentions(key)
|
||||
self.subcommand_not_found,
|
||||
cmd,
|
||||
self.remove_mentions(key),
|
||||
)
|
||||
return await self.send_error_message(string)
|
||||
cmd = found
|
||||
|
|
|
@ -23,10 +23,12 @@ class Inventory:
|
|||
ON DUPLICATE KEY UPDATE quantity = quantity + %s;
|
||||
"""
|
||||
|
||||
database.execute_query(query, (self.user_id, item.id, abs(quantity), abs(quantity)))
|
||||
database.execute_query(
|
||||
query,
|
||||
(self.user_id, item.id, abs(quantity), abs(quantity)),
|
||||
)
|
||||
|
||||
def take_item(self, item: item_service.Item, quantity=1):
|
||||
|
||||
query = """
|
||||
INSERT INTO inventory (user_id, item_id, quantity)
|
||||
VALUES (%s, %s, 0)
|
||||
|
@ -36,7 +38,10 @@ class Inventory:
|
|||
END;
|
||||
"""
|
||||
|
||||
database.execute_query(query, (self.user_id, item.id, self.user_id, item.id, abs(quantity)))
|
||||
database.execute_query(
|
||||
query,
|
||||
(self.user_id, item.id, self.user_id, item.id, abs(quantity)),
|
||||
)
|
||||
|
||||
def get_inventory(self):
|
||||
query = "SELECT item_id, quantity FROM inventory WHERE user_id = %s AND quantity > 0"
|
||||
|
|
|
@ -8,7 +8,9 @@ class CustomReactionsService:
|
|||
pass
|
||||
|
||||
async def find_trigger(
|
||||
self, guild_id: int, message_content: str
|
||||
self,
|
||||
guild_id: int,
|
||||
message_content: str,
|
||||
) -> Optional[Dict[str, Any]]:
|
||||
message_content = message_content.lower()
|
||||
query = """
|
||||
|
@ -21,7 +23,8 @@ class CustomReactionsService:
|
|||
LIMIT 1
|
||||
"""
|
||||
result = database.select_query(
|
||||
query, (guild_id, message_content, message_content, guild_id)
|
||||
query,
|
||||
(guild_id, message_content, message_content, guild_id),
|
||||
)
|
||||
if result:
|
||||
reaction = result[0] # Get the first result from the list
|
||||
|
@ -91,7 +94,7 @@ class CustomReactionsService:
|
|||
"created_at": reaction[10],
|
||||
"updated_at": reaction[11],
|
||||
"type": "emoji" if reaction[4] else "text",
|
||||
}
|
||||
},
|
||||
)
|
||||
return reactions
|
||||
|
||||
|
|
|
@ -18,7 +18,14 @@ class BlackJackStats:
|
|||
VALUES (%s, %s, %s, %s, %s, %s)
|
||||
"""
|
||||
|
||||
values = (self.user_id, self.is_won, self.bet, self.payout, self.hand_player, self.hand_dealer)
|
||||
values = (
|
||||
self.user_id,
|
||||
self.is_won,
|
||||
self.bet,
|
||||
self.payout,
|
||||
self.hand_player,
|
||||
self.hand_dealer,
|
||||
)
|
||||
|
||||
database.execute_query(query, values)
|
||||
|
||||
|
@ -34,15 +41,20 @@ class BlackJackStats:
|
|||
FROM blackjack
|
||||
WHERE user_id = %s;
|
||||
"""
|
||||
(amount_of_games, total_bet,
|
||||
total_payout, winning_amount, losing_amount) = database.select_query(query, (user_id,))[0]
|
||||
(
|
||||
amount_of_games,
|
||||
total_bet,
|
||||
total_payout,
|
||||
winning_amount,
|
||||
losing_amount,
|
||||
) = database.select_query(query, (user_id,))[0]
|
||||
|
||||
return {
|
||||
"amount_of_games": amount_of_games,
|
||||
"total_bet": total_bet,
|
||||
"total_payout": total_payout,
|
||||
"winning_amount": winning_amount,
|
||||
"losing_amount": losing_amount
|
||||
"losing_amount": losing_amount,
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
|
@ -77,7 +89,14 @@ class SlotsStats:
|
|||
VALUES (%s, %s, %s, %s, %s, %s)
|
||||
"""
|
||||
|
||||
values = (self.user_id, self.is_won, self.bet, self.payout, self.spin_type, self.icons)
|
||||
values = (
|
||||
self.user_id,
|
||||
self.is_won,
|
||||
self.bet,
|
||||
self.payout,
|
||||
self.spin_type,
|
||||
self.icons,
|
||||
)
|
||||
|
||||
database.execute_query(query, values)
|
||||
|
||||
|
@ -99,9 +118,15 @@ class SlotsStats:
|
|||
WHERE user_id = %s
|
||||
"""
|
||||
|
||||
(amount_of_games, total_bet,
|
||||
total_payout, games_won_pair, games_won_three_of_a_kind,
|
||||
games_won_three_diamonds, games_won_jackpot) = database.select_query(query, (user_id,))[0]
|
||||
(
|
||||
amount_of_games,
|
||||
total_bet,
|
||||
total_payout,
|
||||
games_won_pair,
|
||||
games_won_three_of_a_kind,
|
||||
games_won_three_diamonds,
|
||||
games_won_jackpot,
|
||||
) = database.select_query(query, (user_id,))[0]
|
||||
|
||||
return {
|
||||
"amount_of_games": amount_of_games,
|
||||
|
@ -110,5 +135,5 @@ class SlotsStats:
|
|||
"games_won_pair": games_won_pair,
|
||||
"games_won_three_of_a_kind": games_won_three_of_a_kind,
|
||||
"games_won_three_diamonds": games_won_three_diamonds,
|
||||
"games_won_jackpot": games_won_jackpot
|
||||
"games_won_jackpot": games_won_jackpot,
|
||||
}
|
||||
|
|
|
@ -30,11 +30,11 @@ class Comic:
|
|||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
xkcd_dict: dict[str, Any],
|
||||
raw_image: bytes | None = None,
|
||||
comic_url: str | None = None,
|
||||
explanation_url: str | None = None,
|
||||
self,
|
||||
xkcd_dict: dict[str, Any],
|
||||
raw_image: bytes | None = None,
|
||||
comic_url: str | None = None,
|
||||
explanation_url: str | None = None,
|
||||
) -> None:
|
||||
self.id: int | None = xkcd_dict.get("num")
|
||||
self.date: datetime.date | None = self._determine_date(xkcd_dict)
|
||||
|
@ -59,7 +59,9 @@ class Comic:
|
|||
"""
|
||||
try:
|
||||
return datetime.date(
|
||||
int(xkcd_dict["year"]), int(xkcd_dict["month"]), int(xkcd_dict["day"])
|
||||
int(xkcd_dict["year"]),
|
||||
int(xkcd_dict["month"]),
|
||||
int(xkcd_dict["day"]),
|
||||
)
|
||||
|
||||
except (KeyError, ValueError):
|
||||
|
@ -102,9 +104,9 @@ class Comic:
|
|||
|
||||
class Client:
|
||||
def __init__(
|
||||
self,
|
||||
api_url: str = "https://xkcd.com",
|
||||
explanation_wiki_url: str = "https://www.explainxkcd.com/wiki/index.php/",
|
||||
self,
|
||||
api_url: str = "https://xkcd.com",
|
||||
explanation_wiki_url: str = "https://www.explainxkcd.com/wiki/index.php/",
|
||||
) -> None:
|
||||
self._api_url = api_url
|
||||
self._explanation_wiki_url = explanation_wiki_url
|
||||
|
@ -154,7 +156,11 @@ class Client:
|
|||
comic_url: str = f"{self._api_url}/{response_dict['num']}/"
|
||||
explanation_url: str = f"{self._explanation_wiki_url}{response_dict['num']}"
|
||||
|
||||
return Comic(response_dict, comic_url=comic_url, explanation_url=explanation_url)
|
||||
return Comic(
|
||||
response_dict,
|
||||
comic_url=comic_url,
|
||||
explanation_url=explanation_url,
|
||||
)
|
||||
|
||||
def _fetch_comic(self, comic_id: int, raw_comic_image: bool) -> Comic:
|
||||
"""
|
||||
|
@ -252,14 +258,19 @@ class Client:
|
|||
HttpError
|
||||
If the request fails.
|
||||
"""
|
||||
comic_url = self.latest_comic_url() if comic_id <= 0 else self.comic_id_url(comic_id)
|
||||
comic_url = (
|
||||
self.latest_comic_url() if comic_id <= 0 else self.comic_id_url(comic_id)
|
||||
)
|
||||
|
||||
try:
|
||||
response = httpx.get(comic_url)
|
||||
response.raise_for_status()
|
||||
|
||||
except httpx.HTTPStatusError as exc:
|
||||
raise HttpError(exc.response.status_code, exc.response.reason_phrase) from exc
|
||||
raise HttpError(
|
||||
exc.response.status_code,
|
||||
exc.response.reason_phrase,
|
||||
) from exc
|
||||
|
||||
return response.text
|
||||
|
||||
|
@ -291,7 +302,10 @@ class Client:
|
|||
response.raise_for_status()
|
||||
|
||||
except httpx.HTTPStatusError as exc:
|
||||
raise HttpError(exc.response.status_code, exc.response.reason_phrase) from exc
|
||||
raise HttpError(
|
||||
exc.response.status_code,
|
||||
exc.response.reason_phrase,
|
||||
) from exc
|
||||
|
||||
return response.content
|
||||
|
||||
|
|
|
@ -52,7 +52,8 @@ class XpService:
|
|||
|
||||
try:
|
||||
user_xp, user_level, cooldown = database.select_query(
|
||||
query, (self.user_id, self.guild_id)
|
||||
query,
|
||||
(self.user_id, self.guild_id),
|
||||
)[0]
|
||||
except (IndexError, TypeError):
|
||||
user_xp, user_level, cooldown = 0, 0, None
|
||||
|
@ -83,14 +84,16 @@ class XpService:
|
|||
ORDER BY user_level DESC, user_xp DESC
|
||||
"""
|
||||
data: List[Tuple[int, int, int]] = database.select_query(
|
||||
query, (self.guild_id,)
|
||||
query,
|
||||
(self.guild_id,),
|
||||
)
|
||||
|
||||
leaderboard: List[Tuple[int, int, int, int]] = [
|
||||
(row[0], row[1], row[2], rank) for rank, row in enumerate(data, start=1)
|
||||
]
|
||||
return next(
|
||||
(entry[3] for entry in leaderboard if entry[0] == self.user_id), None
|
||||
(entry[3] for entry in leaderboard if entry[0] == self.user_id),
|
||||
None,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
|
@ -118,18 +121,20 @@ class XpService:
|
|||
user_xp: int = row[1]
|
||||
user_level: int = row[2]
|
||||
needed_xp_for_next_level: int = XpService.xp_needed_for_next_level(
|
||||
user_level
|
||||
user_level,
|
||||
)
|
||||
|
||||
leaderboard.append(
|
||||
(row_user_id, user_xp, user_level, needed_xp_for_next_level)
|
||||
(row_user_id, user_xp, user_level, needed_xp_for_next_level),
|
||||
)
|
||||
|
||||
return leaderboard
|
||||
|
||||
@staticmethod
|
||||
def generate_progress_bar(
|
||||
current_value: int, target_value: int, bar_length: int = 10
|
||||
current_value: int,
|
||||
target_value: int,
|
||||
bar_length: int = 10,
|
||||
) -> str:
|
||||
"""
|
||||
Generates an XP progress bar based on the current level and XP.
|
||||
|
@ -214,7 +219,8 @@ class XpRewardService:
|
|||
ORDER BY level DESC
|
||||
"""
|
||||
data: List[Tuple[int, int, bool]] = database.select_query(
|
||||
query, (self.guild_id,)
|
||||
query,
|
||||
(self.guild_id,),
|
||||
)
|
||||
return {level: (role_id, persistent) for level, role_id, persistent in data}
|
||||
|
||||
|
@ -239,7 +245,8 @@ class XpRewardService:
|
|||
ON DUPLICATE KEY UPDATE role_id = %s, persistent = %s;
|
||||
"""
|
||||
database.execute_query(
|
||||
query, (self.guild_id, level, role_id, persistent, role_id, persistent)
|
||||
query,
|
||||
(self.guild_id, level, role_id, persistent, role_id, persistent),
|
||||
)
|
||||
self.rewards[level] = (role_id, persistent)
|
||||
|
||||
|
|
Loading…
Reference in a new issue