Repository: python-discord/sir-lancebot
Issue: Handle potential errors in halloweenify command

The `halloweenify` cog will generate a Halloween-themed nickname for the invoking user, and then attempt to set it as a guild nickname.

https://github.com/python-discord/seasonalbot/blob/b45272aa62859abedc1ccc1836f0a61935394e87/bot/exts/halloween/halloweenify.py#L44

It does not currently handle the following situations.

## Lacking permissions

When invoked by a staff member, the bot lacks the required permissions, and a `discord.Forbidden` exception silently kills the command.

The exception should be caught & handled by informing the user that their nickname cannot be changed by the bot, but they can still change it themselves - the bot already also shows an embed with the new name (if it doesn't die before the line is reached).

## No nicknames in DMs

When invoked in DMs, the cog will also fail as `ctx.author` is not an instance of `discord.Member` and has no `edit` method. In such a case, we can still show the generated nickname and inform the user that if they invoke the command in-server, they can have their nickname changed automatically.

While writing the code to handle both situations shouldn't be difficult, a good solution will incorporate the needed information into the response embed in a natural way, with UX in mind.

---

- [ ] I'd like to implement the bug fix
- [x] Anyone can implement the bug fix

Changed files:
bot/exts/halloween/halloweenify.py

diff --git a/bot/exts/halloween/halloweenify.py b/bot/exts/halloween/halloweenify.py
index 5c433a81..a19066cf 100644
--- a/bot/exts/halloween/halloweenify.py
+++ b/bot/exts/halloween/halloweenify.py
@@ -4,6 +4,7 @@ from pathlib import Path
 from random import choice
 
 import discord
+from discord.errors import Forbidden
 from discord.ext import commands
 from discord.ext.commands.cooldowns import BucketType
 
@@ -37,11 +38,25 @@ class Halloweenify(commands.Cog):
                 f"**{ctx.author.display_name}** wasn\\'t spooky enough for you? That\\'s understandable, "
                 f"{ctx.author.display_name} isn\\'t scary at all! "
                 "Let me think of something better. Hmm... I got it!\\n\\n "
-                f"Your new nickname will be: \\n :ghost: **{nickname}** :jack_o_lantern:"
             )
             embed.set_image(url=image)
 
-            await ctx.author.edit(nick=nickname)
+            if isinstance(ctx.author, discord.Member):
+                try:
+                    await ctx.author.edit(nick=nickname)
+                    embed.description += f"Your new nickname will be: \\n:ghost: **{nickname}** :jack_o_lantern:"
+
+                except Forbidden:   # The bot doesn't have enough permission
+                    embed.description += (
+                        f"Your new nickname should be: \\n :ghost: **{nickname}** :jack_o_lantern: \\n\\n"
+                        f"It looks like I cannot change your name, but feel free to change it yourself."
+                    )
+
+            else:   # The command has been invoked in DM
+                embed.description += (
+                    f"Your new nickname should be: \\n :ghost: **{nickname}** :jack_o_lantern: \\n\\n"
+                    f"Feel free to change it yourself, or invoke the command again inside the server."
+                )
 
         await ctx.send(embed=embed)