1
Fork 0
mirror of https://github.com/wlinator/luminara.git synced 2024-10-02 18:03:12 +00:00

Refactor code for emoji conversion and reaction handling

This commit is contained in:
wlinator 2024-07-13 14:51:43 -04:00
parent 370e3f1471
commit 7da002ac4f
9 changed files with 132 additions and 171 deletions

1
.gitignore vendored
View file

@ -11,3 +11,4 @@ __pycache__/
users.yml
db/data/
db/migrations/100-dump.sql
.aider*

View file

@ -20,6 +20,24 @@
"invite_description": "Thanks for inviting me to your server!",
"invite_button_text": "Invite Lumi",
"intro_no_guild": "you're not in a server that supports introductions.",
"intro_no_guild_author": "Server Not Supported",
"intro_no_channel": "the introduction channel is not set, please contact a moderator.",
"intro_no_channel_author": "Channel Not Set",
"intro_too_long": "your answer was too long, please keep it below 200 characters.",
"intro_too_long_author": "Answer Too Long",
"intro_timeout": "you took too long to answer the question, please try again.",
"intro_timeout_author": "Timeout",
"intro_service_name": "Introduction Service",
"intro_question_footer": "Type your answer below.",
"intro_start": "this command will serve as a questionnaire for your entry to {0}. Please keep your answers \"PG-13\" and don't abuse this command.",
"intro_start_footer": "Click the button below to start",
"intro_stopped": "the introduction command was stopped.",
"intro_stopped_author": "Introduction Stopped",
"intro_preview_field": "**{0}:** {1}\n\n",
"intro_post_confirmation": "your introduction has been posted in {0}!",
"intro_content": "Introduction by {0}",
"error_hierarchy": "❌ | **{0}** you can't perform this action because the target user is equal or higher than you in the role hierarchy.",
"error_missing_permissions": "❌ | **{0}** you are missing permissions to run this command.",
@ -29,24 +47,6 @@
"ping": "\uD83C\uDFD3 | **{0}** I'm online.",
"restarting": "Restarting Lumi...",
"restart_error": "Error executing the script: {0}",
"intro_muted": "REMOVED STRING",
"intro_no_perms": "It seems that you don't have permission to do that!",
"intro_start_descr": "This command will serve as a questionnaire for you entry to {0}. Please keep your answers \"PG-13\"",
"intro_start_short": "Click the blue button to use the short form, this one has 6 questions.",
"intro_start_extended": "The green button will start the extended introduction, this one takes a bit longer but gives a more detailed portrayal of you.",
"intro_start_footer": "Please don't abuse this command.",
"intro_nickname": "How would you like to be identified in the server?",
"intro_age": "How old are you?",
"intro_location": "Where do you live?",
"intro_pronouns": "What are your preferred pronouns?",
"intro_likes": "Likes & interests.",
"intro_dislikes": "Dislikes.",
"intro_languages": "Which languages do you speak?",
"intro_sexuality": "What's your sexuality?",
"intro_rel_status": "What's your relationship status?",
"intro_extras": "EXTRAS: job status, zodiac sign, hobbies, etc. Tell us about yourself!",
"intro_recorded": "Recorded answer: {0}",
"intro_display_content": "Introduction by {0}",
"award_error": "Something went wrong. Check console.",
"give_error": "Something funky happened. Let Tess know.",
"gambling_error": "Something went wrong during the gambling command: {0}",

View file

@ -20,9 +20,9 @@ class Constants:
INVITE_LINK = "https://discord.com/oauth2/authorize?client_id=1038050427272429588&permissions=8&scope=bot"
# KRC
KRC_GUILD_ID = 719227135151046699
KRC_INTRO_CHANNEL_ID = 973619250507972618
KRC_QUESTION_MAPPING = resources["guild_specific"]["question_mapping"]
KRC_GUILD_ID: int = 719227135151046699
KRC_INTRO_CHANNEL_ID: int = 973619250507972618
KRC_QUESTION_MAPPING: dict[str, str] = resources["guild_specific"]["question_mapping"]
# logo
LUMI_LOGO_TRANSPARENT = art["logo"]["transparent"]

View file

@ -24,7 +24,7 @@ class EmbedBuilder:
description = f"**{ctx.author.name}** {description}"
if not author_icon_url:
author_icon_url = ctx.author.avatar.url
author_icon_url = ctx.author.display_avatar.url
if not footer_text:
footer_text = "Luminara"
if not footer_icon_url:
@ -45,12 +45,12 @@ class EmbedBuilder:
embed.set_thumbnail(url=thumbnail_url)
return embed
@staticmethod
def create_error_embed(
ctx,
title=None,
author_text=None,
author_icon_url=None,
description=None,
footer_text=None,
show_name=True,
@ -61,7 +61,7 @@ class EmbedBuilder:
ctx,
title=title,
author_text=author_text,
author_icon_url=CONST.CROSS_ICON,
author_icon_url=author_icon_url or CONST.CROSS_ICON,
description=description,
color=CONST.COLOR_ERROR,
footer_text=footer_text,
@ -76,6 +76,7 @@ class EmbedBuilder:
ctx,
title=None,
author_text=None,
author_icon_url=None,
description=None,
footer_text=None,
show_name=True,
@ -86,7 +87,7 @@ class EmbedBuilder:
ctx,
title=title,
author_text=author_text,
author_icon_url=CONST.CHECK_ICON,
author_icon_url=author_icon_url or CONST.CHECK_ICON,
description=description,
color=CONST.COLOR_DEFAULT,
footer_text=footer_text,
@ -101,6 +102,7 @@ class EmbedBuilder:
ctx,
title=None,
author_text=None,
author_icon_url=None,
description=None,
footer_text=None,
show_name=True,
@ -111,7 +113,7 @@ class EmbedBuilder:
ctx,
title=title,
author_text=author_text,
author_icon_url=CONST.EXCLAIM_ICON,
author_icon_url=author_icon_url or CONST.EXCLAIM_ICON,
description=description,
color=CONST.COLOR_DEFAULT,
footer_text=footer_text,
@ -126,6 +128,7 @@ class EmbedBuilder:
ctx,
title=None,
author_text=None,
author_icon_url=None,
description=None,
footer_text=None,
show_name=True,
@ -136,7 +139,7 @@ class EmbedBuilder:
ctx,
title=title,
author_text=author_text,
author_icon_url=CONST.WARNING_ICON,
author_icon_url=author_icon_url or CONST.WARNING_ICON,
description=description,
color=CONST.COLOR_WARNING,
footer_text=footer_text,

View file

@ -202,21 +202,6 @@ class MiscErrors:
return embed
@staticmethod
def intro_no_guild(ctx, client_side=False):
embed = clean_error_embed(ctx)
if not client_side:
embed.description += "you're not in a server that supports introductions."
else:
embed.description += "I'm not in a server that supports introductions."
embed.set_footer(
text="this will be updated soon, stay tuned", icon_url=CONST.EXCLAIM_ICON
)
return embed
class HelpErrors:
@staticmethod
@ -231,39 +216,3 @@ class HelpErrors:
)
return embed
class IntroErrors:
@staticmethod
def timeout(ctx):
embed = clean_error_embed(ctx)
embed.description += "you ran out of time to answer this question."
embed.set_footer(
text=f"Please do {formatter.get_prefix(ctx)}{formatter.get_invoked_name(ctx)} again",
icon_url=exclaim_icon,
)
return embed
@staticmethod
def too_long(ctx):
embed = clean_error_embed(ctx)
embed.description += (
"your answer was too long, please keep it below 200 characters."
)
embed.set_footer(
text=f"Please do {formatter.get_prefix(ctx)}{formatter.get_invoked_name(ctx)} again",
icon_url=CONST.EXCLAIM_ICON,
)
return embed
@staticmethod
def intro_no_channel(ctx):
embed = clean_error_embed(ctx)
embed.description += "the introduction channel is missing."
embed.set_footer(
text="Please contact a server administrator", icon_url=CONST.EXCLAIM_ICON
)
return embed

View file

@ -48,14 +48,7 @@ class MiscInfo:
embed.set_footer(text=f"Latency: {round(1000 * client.latency)}ms", icon_url=exclaim_icon)
return embed
@staticmethod
def invite(ctx):
embed = clean_info_embed(ctx)
embed.description += "thanks for inviting me to your server!"
return embed
@staticmethod
def set_prefix(ctx, prefix):
embed = clean_info_embed(ctx)

View file

@ -11,51 +11,10 @@ def clean_intro_embed(ctx):
return embed
class Questions:
@staticmethod
def question(ctx, text):
embed = clean_intro_embed(ctx)
embed.description += text
embed.set_footer(text="Type your answer below", icon_url=CONST.EXCLAIM_ICON)
return embed
class General:
@staticmethod
def start(ctx, channel):
embed = clean_intro_embed(ctx)
embed.description = (
(embed.description or "")
+ f"this command will serve as a questionnaire for your entry to {channel.mention}. "
f'Please keep your answers "PG-13" and don\'t abuse this command.'
)
embed.set_footer(text="Click the button below to start", icon_url=CONST.EXCLAIM_ICON)
return embed
@staticmethod
def clicked_stop(ctx):
embed = clean_intro_embed(ctx)
embed.description = (
embed.description or ""
) + " the introduction command was stopped."
return embed
@staticmethod
def preview(ctx, answer_mapping: dict):
embed = discord.Embed(
color=discord.Color.blurple(), description=""
) # Corrected color
embed.set_author(name=ctx.author.name, icon_url=ctx.author.avatar.url)
description = ""
for key, answer in answer_mapping.items():
description += f"**{key}:** {answer}\n\n"
embed.description = description
return embed
@staticmethod
def post_confirmation(ctx, channel):
embed = clean_intro_embed(ctx)

View file

@ -1,58 +1,73 @@
import asyncio
from loguru import logger
import discord
from discord.ext import bridge
from config.parser import JsonCache
from lib.interactions.introduction import (
IntroductionStartButtons,
IntroductionFinishButtons,
)
from lib.embeds.error import MiscErrors, IntroErrors
from lib.embeds.intro import General, Questions
from typing import Optional
resources = JsonCache.read_json("resources")
from lib.constants import CONST
from lib.embed_builder import EmbedBuilder
async def cmd(self, ctx: bridge.Context) -> None:
"""
Introduction command for v2 - heavily optimized.
guild: Optional[discord.Guild] = self.client.get_guild(CONST.KRC_GUILD_ID)
member = guild.get_member(ctx.author.id) if guild else None
Args:
self (LumiBot): The instance of the LumiBot.
ctx (bridge.Context): The context of the command invocation.
"""
# For now, this command is only supported in one guild.
# Therefore, we check if the user is in that guild.
guild: Optional[discord.Guild] = self.client.get_guild(
int(resources["guild_specific"]["guild_id"])
)
if guild is None:
await ctx.respond(embed=MiscErrors.intro_no_guild(ctx))
if guild is None or member is None:
await ctx.respond(
embed=EmbedBuilder.create_error_embed(
ctx,
author_text=CONST.STRINGS["intro_no_guild_author"],
description=CONST.STRINGS["intro_no_guild"],
footer_text=CONST.STRINGS["intro_service_name"],
)
)
return
# A list of questions and corresponding field names
# This won't be hardcoded in the future (db update)
question_mapping: dict[str, str] = resources["guild_specific"]["question_mapping"]
question_mapping: dict[str, str] = CONST.KRC_QUESTION_MAPPING
channel: Optional[discord.abc.GuildChannel] = guild.get_channel(
CONST.KRC_INTRO_CHANNEL_ID
)
# channel = await self.client.convert_to_text_channel(
# ctx, int(resources["guild_specific"]["intro_channel_id"])
# )
channel: Optional[discord.abc.GuildChannel] = guild.get_channel(int(resources["guild_specific"]["intro_channel_id"]))
if channel is None or isinstance(channel, discord.ForumChannel) or isinstance(channel, discord.CategoryChannel):
await ctx.respond(embed=IntroErrors.intro_no_channel(ctx))
if (
channel is None
or isinstance(channel, discord.ForumChannel)
or isinstance(channel, discord.CategoryChannel)
):
await ctx.respond(
embed=EmbedBuilder.create_error_embed(
ctx,
author_text=CONST.STRINGS["intro_no_channel_author"],
description=CONST.STRINGS["intro_no_channel"],
footer_text=CONST.STRINGS["intro_service_name"],
)
)
return
view = IntroductionStartButtons(ctx)
await ctx.respond(embed=General.start(ctx, channel), view=view)
# await ctx.respond(embed=General.start(ctx, channel), view=view)
await ctx.respond(
embed=EmbedBuilder.create_embed(
ctx,
author_text=CONST.STRINGS["intro_service_name"],
description=CONST.STRINGS["intro_start"].format(channel.mention),
footer_text=CONST.STRINGS["intro_start_footer"],
),
view=view,
)
await view.wait()
if view.clickedStop:
await ctx.send(embed=General.clicked_stop(ctx))
await ctx.send(
embed=EmbedBuilder.create_embed(
ctx,
author_text=CONST.STRINGS["intro_stopped_author"],
description=CONST.STRINGS["intro_stopped"],
)
)
return
elif view.clickedStart:
@ -65,7 +80,14 @@ async def cmd(self, ctx: bridge.Context) -> None:
answer_mapping: dict[str, str] = {}
for key, question in question_mapping.items():
await ctx.send(embed=Questions.question(ctx, question))
await ctx.send(
embed=EmbedBuilder.create_embed(
ctx,
author_text=key,
description=question,
footer_text=CONST.STRINGS["intro_question_footer"],
)
)
try:
answer: discord.Message = await self.client.wait_for(
@ -74,15 +96,39 @@ async def cmd(self, ctx: bridge.Context) -> None:
answer_mapping[key] = answer.content.replace("\n", " ")
if len(answer_mapping[key]) > 200:
await ctx.send(embed=IntroErrors.too_long(ctx))
await ctx.send(
embed=EmbedBuilder.create_error_embed(
ctx,
author_text=CONST.STRINGS["intro_too_long_author"],
description=CONST.STRINGS["intro_too_long"],
footer_text=CONST.STRINGS["intro_service_name"],
)
)
return
except asyncio.TimeoutError:
await ctx.send(embed=IntroErrors.timeout(ctx))
await ctx.send(
embed=EmbedBuilder.create_error_embed(
ctx,
author_text=CONST.STRINGS["intro_timeout_author"],
description=CONST.STRINGS["intro_timeout"],
footer_text=CONST.STRINGS["intro_service_name"],
)
)
return
# Generate a preview of the introduction, and send it on confirmation.
preview: discord.Embed = General.preview(ctx, answer_mapping)
# preview: discord.Embed = General.preview(ctx, answer_mapping)
description = ""
for key, value in answer_mapping.items():
description += CONST.STRINGS["intro_preview_field"].format(key, value)
preview = EmbedBuilder.create_embed(
ctx,
author_text=ctx.author.name,
author_icon_url=ctx.author.display_avatar.url,
description=description,
footer_text=CONST.STRINGS["intro_service_name"],
)
view = IntroductionFinishButtons(ctx)
await ctx.send(embed=preview, view=view)
@ -90,15 +136,24 @@ async def cmd(self, ctx: bridge.Context) -> None:
if view.clickedConfirm:
await channel.send(
embed=preview, content=f"Introduction by {ctx.author.mention}"
embed=preview, content=CONST.STRINGS["intro_content"].format(ctx.author.mention)
)
await ctx.send(embed=General.post_confirmation(ctx, channel))
logger.debug(
f"Introduction by {ctx.author.name} was submitted in guild {guild.name} ({guild.id})."
await ctx.send(
embed=EmbedBuilder.create_embed(
ctx,
description=CONST.STRINGS["intro_post_confirmation"].format(
channel.mention
),
)
)
return
else:
await ctx.send(embed=General.clicked_stop(ctx))
await ctx.send(
embed=EmbedBuilder.create_embed(
ctx,
author_text=CONST.STRINGS["intro_stopped_author"],
description=CONST.STRINGS["intro_stopped"],
)
)
return

View file

@ -5,4 +5,5 @@ dropbox==11.36.2
mariadb==1.1.10
psutil==5.9.8
httpx==0.27.0
loguru==0.7.2
loguru==0.7.2
aider-chat