Skip to content
59 changes: 49 additions & 10 deletions bot/exts/utilities/conversationstarters.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,27 +41,61 @@ def __init__(self, bot: Bot):
self.bot = bot

@staticmethod
def _build_topic_embed(channel_id: int) -> discord.Embed:
def _build_topic_embed(channel_id: int, previous_description: None | str) -> tuple[discord.Embed, bool]:
"""
Build an embed containing a conversation topic.

If in a Python channel, a python-related topic will be given.
Otherwise, a random conversation topic will be received by the user.

Also returns a value that determines whether to remove the reaction afterwards
"""
# No matter what, the form will be shown.
footer = f"Suggest more topics [here]({SUGGESTION_FORM})!"
max_topics = 3

# Remove footer from previous description
previous_topic = None
if previous_description:
previous_topic = previous_description.split("\n\n")[0]

embed = discord.Embed(
description=f"Suggest more topics [here]({SUGGESTION_FORM})!",
title="Conversation Starter",
color=discord.Colour.og_blurple()
)

try:
channel_topics = TOPICS[channel_id]
channel_topics = TOPICS[str(channel_id)]
except KeyError:
# Channel doesn't have any topics.
embed.title = f"**{next(TOPICS['default'])}**"
new_topic = next(TOPICS["default"])
else:
embed.title = f"**{next(channel_topics)}**"
return embed
new_topic = next(channel_topics)

def add_description(text: str) -> None:
embed.description = f"{text}\n\n{footer}"

if previous_topic is None:
# This is the first topic being sent
add_description(new_topic)
return embed, False

total_topics = previous_topic.count("\n") + 1

# Handle forced reactions after clear
if total_topics >= max_topics:
embed.description = previous_description
return embed, True

# Add 1 before first topic
if total_topics == 1:
previous_topic = f"1. {previous_topic}"

add_description(f"{previous_topic}\n{total_topics + 1}. {new_topic}")

# If this is the last topic, remove the reaction
if total_topics == max_topics - 1:
return embed, True
return embed, False

@staticmethod
def _predicate(
Expand Down Expand Up @@ -99,23 +133,28 @@ async def _listen_for_refresh(
break

try:
await message.edit(embed=self._build_topic_embed(message.channel.id))
# The returned discord.Message object from discord.Message.edit is different from the current
# discord.Message object, so it must be reassigned to update properly
embed, remove_reactions = self._build_topic_embed(message.channel.id, message.embeds[0].description)
message = await message.edit(embed=embed)
if remove_reactions:
await message.clear_reaction("🔄")
except discord.NotFound:
break

with suppress(discord.NotFound):
await message.remove_reaction(reaction, user)

@commands.command()
@commands.cooldown(1, 60*2, commands.BucketType.channel)
@commands.cooldown(1, 60 * 2, commands.BucketType.channel)
@whitelist_override(channels=ALL_ALLOWED_CHANNELS)
async def topic(self, ctx: commands.Context) -> None:
"""
Responds with a random topic to start a conversation.

Allows the refresh of a topic by pressing an emoji.
"""
message = await ctx.send(embed=self._build_topic_embed(ctx.channel.id))
message = await ctx.send(embed=self._build_topic_embed(ctx.channel.id, None)[0])
self.bot.loop.create_task(self._listen_for_refresh(ctx.author, message))


Expand Down