I recently created a Discord application using discord.py to handle applications for my server.
There's a /apply
function which sends an embed and a "ReviewView" to our staff channel.
class ReviewView(View):
def __init__(self, embed_user:discord.user, floor:int):
super().__init__()
self.embed_user = embed_user
self.floor=floor
@discord.ui.button(label="Accept", style=discord.ButtonStyle.success)
async def approve(self, interaction: discord.Interaction, button: discord.ui.Button):
embed = interaction.message.embeds[0]
embed.color = discord.Color.green()
role = get(self.embed_user.guild.roles, name=f"F{self.floor} Carrier")
user = self.embed_user
user_roles = [role.name for role in user.roles]
if not any(role=="Carry Team" for role in user_roles):
carry_team = get(interaction.guild.roles, name=f"Carry Team")
await user.add_roles(carry_team)
try:
dm_embed = discord.Embed(title=f"Your dungeon floor {self.floor} application has been accepted", description="Thank you for joining our carrier program. You will be pinged when a carry service that you provide is requested!")
dm_embed.add_field(name="Rules", value="<#990437238926110730>")
dm_embed.add_field(name="Accepted By", value=f"{interaction.user.mention}", inline=False)
dm_embed.set_author(name=interaction.user.name, icon_url=interaction.user.display_avatar.url)
dm_embed.timestamp = interaction.created_at
dm_embed.color=discord.Color.green()
await user.send(embed=dm_embed)
await interaction.message.edit(embed=embed)
await self.embed_user.add_roles(role)
await interaction.response.send_message(f"{self.embed_user.mention}'s application accepted by {interaction.user.mention}", ephemeral=False)
#This is just a lazy way to deal with when the user turns off server dms
except Exception:
carrier_chat=interaction.guild.get_channel(990438688561463297)
await interaction.message.edit(embed=embed)
await self.embed_user.add_roles(role)
await interaction.response.send_message(f"{self.embed_user.mention}'s application accepted by {interaction.user.mention}", ephemeral=False)
await carrier_chat.send(embed=dm_embed)
pass
I stored the discord user object into the embed like this
view = ReviewView(embed_user=interaction.user, floor=floor)
This had been working fine when I tested it myself, but whenever the debug console shows "Shared ID None has successfully RESUMED session" after an application, the view simply won't work anymore.
It only returns "This interaction failed" and nothing shows up in the console.
Any ideas would be great! Let me know if there's more information needed
I believe the issue is because by default discord views are not persistent. This means that when the bot restarts or in your case, the session pauses, and then resumes, the bot no longer has access to the view.
In order to fix this you would need to create a persistent view. According to the this example in the discord.py repository , to make a persistent view, you view must have a timeout set to none and every item in the view must have a custom id. Set the timeout to None
def __init__(self, embed_user:discord.user, floor:int):
super().__init__(timeout=None)
Create a custom id for the button:
@discord.ui.button(label="Accept", style=discord.ButtonStyle.success,custom_id='acceptbutton')
If you are making multiple instances of the view I believe you will need to generate unique custom ids so that the button ids do not conflict.
Additionally if you want to make sure you can use the view even after restarting the bot, you would need to add the view to your bot on startup as seen in this post
@bot.event
async def on_ready():
bot.add_view(ReviewView())
However it would be best to use a setup_hook to add the view instead of adding it in on_ready()
async def setup_hook(bot):
bot.add_view(ReviewView())
I believe should fix the issue but I would also recommend reading the documentation on persistent views.