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:
parent
370e3f1471
commit
7da002ac4f
9 changed files with 132 additions and 171 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -11,3 +11,4 @@ __pycache__/
|
|||
users.yml
|
||||
db/data/
|
||||
db/migrations/100-dump.sql
|
||||
.aider*
|
||||
|
|
|
@ -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}",
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
Loading…
Reference in a new issue