[Core] Add Red.message_eligible_as_command (#4077)

* [Core] Add `Red.message_eligible_as_command`

  - This is a small utility function which makes it easy for cog
  creators to treat non-command messages as commands correctly.

  - This also modifies `Red.ignored_channel_or_guild`'s signature to
  explicitly add support for passing a message object (the only needed
  attributes are entirely shared with context)

* Update redbot/core/bot.py

Co-authored-by: jack1142 <6032823+jack1142@users.noreply.github.com>

* address review

* Rename

* remove webhhok check, the issue wasn't possible under normal operation

* Ah yes, ctx.bot in a method of the bot...

Co-authored-by: jack1142 <6032823+jack1142@users.noreply.github.com>
This commit is contained in:
Michael H 2020-07-18 09:38:57 -04:00 committed by GitHub
parent c9ce4a78e6
commit 1852420b98
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 52 additions and 29 deletions

View File

@ -3,7 +3,6 @@ import inspect
import logging
import os
import platform
import re
import shutil
import sys
import contextlib
@ -19,7 +18,6 @@ from typing import (
Dict,
NoReturn,
Set,
Coroutine,
TypeVar,
Callable,
Awaitable,
@ -30,7 +28,6 @@ from types import MappingProxyType
import discord
from discord.ext import commands as dpy_commands
from discord.ext.commands import when_mentioned_or
from discord.ext.commands.bot import BotBase
from . import Config, i18n, commands, errors, drivers, modlog, bank
from .cog_manager import CogManager, CogManagerUI
@ -406,14 +403,60 @@ class RedBase(
return True
async def ignored_channel_or_guild(self, ctx: commands.Context) -> bool:
async def message_eligible_as_command(self, message: discord.Message) -> bool:
"""
Runs through the things which apply globally about commands
to determine if a message may be responded to as a command.
This can't interact with permissions as permissions is hyper-local
with respect to command objects, create command objects for this
if that's needed.
This also does not check for prefix or command conflicts,
as it is primarily designed for non-prefix based response handling
via on_message_without_command
Parameters
----------
message
The message object to check
Returns
-------
bool
Whether or not the message is eligible to be treated as a command.
"""
channel = message.channel
guild = message.guild
if message.author.bot:
return False
if guild:
assert isinstance(channel, discord.abc.GuildChannel) # nosec
if not channel.permissions_for(guild.me).send_messages:
return False
if not (await self.ignored_channel_or_guild(message)):
return False
if not (await self.allowed_by_whitelist_blacklist(message.author)):
return False
return True
async def ignored_channel_or_guild(
self, ctx: Union[commands.Context, discord.Message]
) -> bool:
"""
This checks if the bot is meant to be ignoring commands in a channel or guild,
as considered by Red's whitelist and blacklist.
Parameters
----------
ctx : Context of where the command is being run.
ctx :
Context object of the command which needs to be checked prior to invoking
or a Message object which might be intended for use as a command.
Returns
-------
@ -424,8 +467,8 @@ class RedBase(
surpass_ignore = (
isinstance(ctx.channel, discord.abc.PrivateChannel)
or perms.manage_guild
or await ctx.bot.is_owner(ctx.author)
or await ctx.bot.is_admin(ctx.author)
or await self.is_owner(ctx.author)
or await self.is_admin(ctx.author)
)
if surpass_ignore:
return True

View File

@ -4,25 +4,5 @@ from . import commands
def init_global_checks(bot):
@bot.check_once
def minimum_bot_perms(ctx) -> bool:
"""
Too many 403, 401, and 429 Errors can cause bots to get global'd
It's reasonable to assume the below as a minimum amount of perms for
commands.
"""
return ctx.channel.permissions_for(ctx.me).send_messages
@bot.check_once
async def whiteblacklist_checks(ctx) -> bool:
return await ctx.bot.allowed_by_whitelist_blacklist(ctx.author)
@bot.check_once
async def ignore_checks(ctx) -> bool:
"""Check the channel or server is not ignored"""
return await ctx.bot.ignored_channel_or_guild(ctx)
@bot.check_once
def bots(ctx) -> bool:
"""Check the user is not another bot."""
return not ctx.author.bot
async def check_message_is_eligible_as_command(ctx: commands.Context) -> bool:
return await ctx.bot.message_eligible_as_command(ctx.message)