diff options
Diffstat (limited to '')
| -rw-r--r-- | Pipfile.lock | 8 | ||||
| -rw-r--r-- | bot/exts/backend/error_handler.py | 40 | ||||
| -rw-r--r-- | bot/exts/info/tags.py | 24 | 
3 files changed, 63 insertions, 9 deletions
| diff --git a/Pipfile.lock b/Pipfile.lock index fbae5b3db..3f9c32d62 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -580,7 +580,7 @@                  "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1",                  "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"              ], -            "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", +            "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2'",              "version": "==2.4.7"          },          "pyreadline": { @@ -655,7 +655,7 @@                  "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259",                  "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"              ], -            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", +            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'",              "version": "==1.15.0"          },          "snowballstemmer": { @@ -1097,7 +1097,7 @@                  "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259",                  "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"              ], -            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", +            "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'",              "version": "==1.15.0"          },          "snowballstemmer": { @@ -1112,7 +1112,7 @@                  "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",                  "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"              ], -            "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", +            "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2'",              "version": "==0.10.2"          },          "urllib3": { diff --git a/bot/exts/backend/error_handler.py b/bot/exts/backend/error_handler.py index 5b5840858..2402fa175 100644 --- a/bot/exts/backend/error_handler.py +++ b/bot/exts/backend/error_handler.py @@ -1,4 +1,5 @@  import contextlib +import difflib  import logging  import typing as t @@ -8,7 +9,7 @@ from sentry_sdk import push_scope  from bot.api import ResponseCodeError  from bot.bot import Bot -from bot.constants import Colours +from bot.constants import Channels, Colours, Icons, MODERATION_ROLES  from bot.converters import TagNameConverter  from bot.errors import LockedResourceError  from bot.utils.checks import InWhitelistCheckFailure @@ -155,9 +156,46 @@ class ErrorHandler(Cog):          else:              with contextlib.suppress(ResponseCodeError):                  await ctx.invoke(tags_get_command, tag_name=tag_name) + +        if not any(role.id in MODERATION_ROLES for role in ctx.author.roles): +            tags_cog = self.bot.get_cog("Tags") +            command_name = ctx.invoked_with +            sent = await tags_cog.display_tag(ctx, command_name) + +            if not sent: +                await self.send_command_suggestion(ctx, command_name) +          # Return to not raise the exception          return +    async def send_command_suggestion(self, ctx: Context, command_name: str) -> None: +        """Sends user similar commands if any can be found.""" +        # No similar tag found, or tag on cooldown - +        # searching for a similar command +        raw_commands = [] +        for cmd in self.bot.walk_commands(): +            if not cmd.hidden: +                raw_commands += (cmd.name, *cmd.aliases) +        if similar_command_data := difflib.get_close_matches(command_name, raw_commands, 1): +            similar_command_name = similar_command_data[0] +            similar_command = self.bot.get_command(similar_command_name) + +            log_msg = "Cancelling attempt to suggest a command due to failed checks." +            try: +                if not await similar_command.can_run(ctx): +                    log.debug(log_msg) +                    return +            except errors.CommandError as cmd_error: +                log.debug(log_msg) +                await self.on_command_error(ctx, cmd_error) +                return + +            misspelled_content = ctx.message.content +            e = Embed() +            e.set_author(name="Did you mean:", icon_url=Icons.questionmark) +            e.description = f"{misspelled_content.replace(command_name, similar_command_name, 1)}" +            await ctx.send(embed=e, delete_after=10.0) +      async def handle_user_input_error(self, ctx: Context, e: errors.UserInputError) -> None:          """          Send an error message in `ctx` for UserInputError, sometimes invoking the help command too. diff --git a/bot/exts/info/tags.py b/bot/exts/info/tags.py index da4154316..639286d90 100644 --- a/bot/exts/info/tags.py +++ b/bot/exts/info/tags.py @@ -182,10 +182,15 @@ class Tags(Cog):          matching_tags = self._get_tags_via_content(any, keywords or 'any', ctx.author)          await self._send_matching_tags(ctx, keywords, matching_tags) -    @tags_group.command(name='get', aliases=('show', 'g')) -    async def get_command(self, ctx: Context, *, tag_name: TagNameConverter = None) -> None: -        """Get a specified tag, or a list of all tags if no tag is specified.""" +    async def display_tag(self, ctx: Context, tag_name: str = None) -> bool: +        """ +        If a tag is not found, display similar tag names as suggestions. +        If a tag is not specified, display a paginated embed of all tags. + +        Tags are on cooldowns on a per-tag, per-channel basis. If a tag is on cooldown, display +        nothing and return False. +        """          def _command_on_cooldown(tag_name: str) -> bool:              """              Check if the command is currently on cooldown, on a per-tag, per-channel basis. @@ -212,7 +217,7 @@ class Tags(Cog):                  f"{ctx.author} tried to get the '{tag_name}' tag, but the tag is on cooldown. "                  f"Cooldown ends in {time_left:.1f} seconds."              ) -            return +            return False          if tag_name is not None:              temp_founds = self._get_tag(tag_name) @@ -237,6 +242,7 @@ class Tags(Cog):                      await ctx.send(embed=Embed.from_dict(tag['embed'])),                      [ctx.author.id],                  ) +                return True              elif founds and len(tag_name) >= 3:                  await wait_for_deletion(                      await ctx.send( @@ -247,6 +253,7 @@ class Tags(Cog):                      ),                      [ctx.author.id],                  ) +                return True          else:              tags = self._cache.values() @@ -255,6 +262,7 @@ class Tags(Cog):                      description="**There are no tags in the database!**",                      colour=Colour.red()                  )) +                return True              else:                  embed: Embed = Embed(title="**Current tags**")                  await LinePaginator.paginate( @@ -268,6 +276,14 @@ class Tags(Cog):                      empty=False,                      max_lines=15                  ) +                return True + +        return False + +    @tags_group.command(name='get', aliases=('show', 'g')) +    async def get_command(self, ctx: Context, *, tag_name: TagNameConverter = None) -> None: +        """Get a specified tag, or a list of all tags if no tag is specified.""" +        await self.display_tag(ctx, tag_name)  def setup(bot: Bot) -> None: | 
