Repository: Cog-Creators/Red-DiscordBot

Issue:
[dev] `mock` does not response.
### What Red version are you using?

3.5.0.dev1

### What were you trying to do?

`[p]mock userid ping`

### What did you expect to happen?

That it would send `pong`.

### What actually happened?

It instead sent errors to logs and nothing happened.

```py
ERROR [discord.client] Ignoring exception in on_message
  File "discord/client.py", line 409, in _run_event
    await coro(*args, **kwargs)
  File "redbot/core/events.py", line 345, in on_message
    await bot.process_commands(message)
  File "redbot/core/bot.py", line 1348, in process_commands
    await self.invoke(ctx)
  File "discord/ext/commands/bot.py", line 1349, in invoke
    if await self.can_run(ctx, call_once=True):
  File "discord/ext/commands/bot.py", line 483, in can_run
    return await discord.utils.async_all(f(ctx) for f in data)
  File "discord/utils.py", line 674, in async_all
    elem = await elem
  File "redbot/core/global_checks.py", line 8, in check_message_is_eligible_as_command
    return await ctx.bot.message_eligible_as_command(ctx.message)
  File "redbot/core/bot.py", line 829, in message_eligible_as_command
    if not (await self.ignored_channel_or_guild(message)):
  File "redbot/core/bot.py", line 862, in ignored_channel_or_guild
    perms = ctx.channel.permissions_for(ctx.author)
  File "discord/channel.py", line 233, in permissions_for
    base = super().permissions_for(obj)
  File "discord/abc.py", line 725, in permissions_for
    roles = obj._roles
   AttributeError: 'User' object has no attribute '_roles'
   ```

### How can we reproduce this error?

1. [p]mock userid ping
2. check logs.

### Anything else?

_No response_


Discussion:
Do we want to actually support the usage of `[p]mock` and `[p]mockuser` in DMs? It's always been only sort of supported but I'm wondering how useful it is. Proper mocking of a DM message would mean that you wouldn't be able to see the result of it as we would have to mock `msg.channel` to that user's DM channel (which we currently are not doing but that creates a significant discrepancy I feel like).

If we were to support mocking DMs, it would have to:
- only be done if the command is used in DM
- set `msg.channel` to user's DM channel (which one can get with `await user.create_dm()`)
- probably go back to using `discord.Member` converter so that we at least get a user that we share a server with; note that we would have to later get a corresponding `discord.User` object for that member and set *that* under `msg.author`

If we just want to drop support for DMs, then it's simpler and all that needs to be done is:
- going back to using `discord.Member`
- adding `@commands.guild_only()` decorator
Think dropping support would be the best and easiest solution here.
I agree though I think we should wait to see if anyone has some feedback about how they find this functionality useful. The previous implementation (3.4.x) is broken either way so even if the fix would be to *properly* support mocking DMs, it could still break some people's use cases. That part is inevitable since keeping a partially broken behavior isn't a good idea but either way it would be good to learn about whether there are reasons we might want to consider properly supporting mocking DMs over completely dropping it.

Since dropping the functionality is simple to implement, it probably won't hurt to give it a few days before we go ahead with it.
If I'm gonna be completely honest, I definitely don't find it useful in dms, I only find it useful in a discord text channels were I can freely use any ids of a user to test if the command(s) has the correct checks for example or any testing purpose related things.

Resolving patch:
diff --git a/redbot/core/dev_commands.py b/redbot/core/dev_commands.py
--- a/redbot/core/dev_commands.py
+++ b/redbot/core/dev_commands.py
@@ -359,9 +359,10 @@ async def pause(self, ctx, toggle: Optional[bool] = None):
         else:
             await ctx.send(_("The REPL session in this channel is now paused."))
 
+    @commands.guild_only()
     @commands.command()
     @checks.is_owner()
-    async def mock(self, ctx, user: discord.User, *, command):
+    async def mock(self, ctx, user: discord.Member, *, command):
         """Mock another user invoking a command.
 
         The prefix must not be entered.
@@ -372,9 +373,10 @@ async def mock(self, ctx, user: discord.User, *, command):
 
         ctx.bot.dispatch("message", msg)
 
+    @commands.guild_only()
     @commands.command(name="mockmsg")
     @checks.is_owner()
-    async def mock_msg(self, ctx, user: discord.User, *, content: str = ""):
+    async def mock_msg(self, ctx, user: discord.Member, *, content: str = ""):
         """Dispatch a message event as if it were sent by a different user.
 
         Current message is used as a base (including attachments, embeds, etc.),


Test patch: