diff options
| author | 2018-04-10 23:05:42 +0100 | |
|---|---|---|
| committer | 2018-04-10 23:05:42 +0100 | |
| commit | 7554e7d25ca67b23590f9206b11ba7437d826265 (patch) | |
| tree | 5ab124006651897bded7f50aa86ed685f3ac092b | |
| parent | Snowflakes should be sent to the site as strings (diff) | |
| parent | Update CONTRIBUTING.md (diff) | |
Merge remote-tracking branch 'origin/master'
Diffstat (limited to '')
| -rw-r--r-- | .github/CONTRIBUTING.md | 42 | ||||
| -rw-r--r-- | Pipfile.lock | 22 | ||||
| -rw-r--r-- | bot/__init__.py | 2 | ||||
| -rw-r--r-- | bot/cogs/tags.py | 161 | ||||
| -rw-r--r-- | tox.ini | 2 | 
5 files changed, 163 insertions, 66 deletions
| diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 000000000..8b803acad --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,42 @@ +# Contributing to one of our projects + +Our projects are open-source, and are deployed as commits are pushed to the `master` branch on each repository. +We've created a set of guidelines here in order to keep everything clean and in working order. Please note that +contributions may be rejected on the basis of a contributor failing to follow the guidelines. + +## Rules + +1. **No force-pushes** or modifying the Git history in any way. +1. If you have direct access to the repository, **create a branch for your changes** and create a pull request for that branch. +   If not, fork it and work on a separate branch there. +    * Some repositories require this and will reject any direct pushes to `master`. Make this a habit! +1. If someone is working on a pull request, **do not open your own pull request for the same task**. Instead, leave some comments +   on the existing pull request. Communication is key, and there's no point in two separate implementations of the same thing. +    * One option is to fork the other contributor's repository, and submit your changes to their branch with your  +      own pull request. If you do this, we suggest following these guidelines when interacting with their repository  +      as well. +1. **Adhere to the prevailing code style**, which we enforce using [flake8](http://flake8.pycqa.org/en/latest/index.html). +    * Additionally, run `flake8` against your code before you push it. Your commit will be rejected by the build server  +      if it fails to lint. For an automatic way to do this, check out  +      [our article on Git hooks](https://github.com/discord-python/site/wiki/Git-Hooks). +1. **Don't fight the framework**. Every framework has its flaws, but the frameworks we've picked out have been carefully  +    chosen for their particular merits. If you can avoid it, please resist reimplementing swathes of framework logic - the +    work has already been done for you! +1. **Work as a team** and cooperate where possible. Keep things friendly, and help each other out - these are shared +    projects, and nobody likes to have their feet trodden on. +1. **Internal projects are internal**. As a contributor, you have access to information that the rest of the server +    does not. With this trust comes responsibility - do not release any information you have learned as a result of +    your contributor position. We are very strict about announcing things at specific times, and many staff members +    will not appreciate a disruption of the announcement schedule. + +Above all, the needs of our community should come before the wants of an individual. Work together, build solutions to +problems and try to do so in a way that people can learn from easily. Abuse of our trust may result in the loss of your Contributor role, especially in relation to Rule 7. + +## Changes to this arrangement + +All projects evolve over time, and this contribution guide is no different. This document may also be subject to pull  +requests or changes by contributors, where you believe you have something valuable to add or change. + +## Footnotes + +This document was inspired by the [Glowstone contribution guidelines](https://github.com/GlowstoneMC/Glowstone/blob/dev/docs/CONTRIBUTING.md). diff --git a/Pipfile.lock b/Pipfile.lock index 11a76eeae..c7c2cca1b 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -70,10 +70,10 @@          },          "dulwich": {              "hashes": [ -                "sha256:91aad98f37a5494c6eabf08c78ed2b6e1b1ce6e7a5556406245d8763a352b99e" +                "sha256:c51e10c260543240e0806052af046e1a78b98cbe1ac1ef3880a78d2269e09da4"              ],              "index": "pypi", -            "version": "==0.19.0" +            "version": "==0.19.2"          },          "idna": {              "hashes": [ @@ -256,10 +256,10 @@          },          "dparse": {              "hashes": [ -                "sha256:7c9f9175d8fd83aed6d31a16c1a3ba4c38189120f1df416b46029d940b4ef582", -                "sha256:e4b479dd4d6078ba5f087b28447a50eee0caed57f135b0f5a5e5d5024390f41d" +                "sha256:00a5fdfa900629e5159bf3600d44905b333f4059a3366f28e0dbd13eeab17b19", +                "sha256:cef95156fa0adedaf042cd42f9990974bec76f25dfeca4dc01f381a243d5aa5b"              ], -            "version": "==0.2.1" +            "version": "==0.4.1"          },          "flake8": {              "hashes": [ @@ -360,10 +360,10 @@          },          "pbr": {              "hashes": [ -                "sha256:8b9a7c3704657cb0831b3ded0a6b61377947c8235b76649bb7de4bfe2e6cfa56", -                "sha256:cf66675e22ae91a4f20e4b8354f117d3e3d1de651513051d109cc39645fb3672" +                "sha256:56b7a8ba7d64bf6135a9dfefb85a80d95924b3fde5ed6343a1a1d464a040dae3", +                "sha256:de75cf1d510542c746beeff66b52241eb12c8f95f2ef846ee50ed5d72392caa4"              ], -            "version": "==4.0.0" +            "version": "==4.0.1"          },          "pycodestyle": {              "hashes": [ @@ -420,11 +420,11 @@          },          "safety": {              "hashes": [ -                "sha256:9fb74211a0a0ab09541fe894293d66a558b6138a9fe8ebabc8cf56670e8a009c", -                "sha256:ff0c4b76ad791d33825e36c41671ea45330d438921e5395903c0e87e576a377a" +                "sha256:0bd2a26b872668767c6db8efecfc8869b547463bedff5e7cd7b52f037aa6f200", +                "sha256:fc3fc55656f1c909d65311b49a38211c42c937f57a05393289fb3f17cadfa4a1"              ],              "index": "pypi", -            "version": "==1.7.0" +            "version": "==1.8.1"          },          "six": {              "hashes": [ diff --git a/bot/__init__.py b/bot/__init__.py index df76215e6..071ec6c98 100644 --- a/bot/__init__.py +++ b/bot/__init__.py @@ -137,7 +137,7 @@ def _get_word(self) -> str:          args = ast.literal_eval(args)          # Force args into container -        if isinstance(args, str): +        if not isinstance(args, tuple):              args = (args,)          # Type validate and format diff --git a/bot/cogs/tags.py b/bot/cogs/tags.py index e4719e124..645835f53 100644 --- a/bot/cogs/tags.py +++ b/bot/cogs/tags.py @@ -1,7 +1,9 @@  import logging +import random  import time +from typing import Optional -from discord import Colour, Embed +from discord import Colour, Embed, User  from discord.ext.commands import AutoShardedBot, Context, command  from bot.constants import ADMIN_ROLE, MODERATOR_ROLE, OWNER_ROLE, SITE_API_KEY, SITE_API_TAGS_URL, TAG_COOLDOWN @@ -16,6 +18,18 @@ class Tags:      Save new tags and fetch existing tags.      """ +    FAIL_TITLES = [ +        "Please don't do that.", +        "You have to stop.", +        "Do you mind?", +        "In the future, don't do that.", +        "That was a mistake.", +        "You blew it.", +        "You're bad at computers.", +        "Are you trying to kill me?", +        "Noooooo!!" +    ] +      def __init__(self, bot: AutoShardedBot):          self.bot = bot          self.tag_cooldowns = {} @@ -84,6 +98,59 @@ class Tags:          return tag_data +    @staticmethod +    async def validate(author: User, tag_name: str, tag_content: str = None) -> Optional[Embed]: +        """ +        Create an embed based on the validity of a tag's name and content + +        :param author: The user that called the command +        :param tag_name: The name of the tag to validate. +        :param tag_content: The tag's content, if any. +        :return: A validation embed if invalid, otherwise None +        """ + +        def is_number(value): +            try: +                float(value) +            except ValueError: +                return False +            else: +                return True + +        embed = Embed() +        embed.colour = Colour.red() + +        # 'tag_name' has at least one invalid character. +        if ascii(tag_name)[1:-1] != tag_name: +            log.warning(f"{author} tried to put an invalid character in a tag name. " +                        "Rejecting the request.") +            embed.description = "Don't be ridiculous, you can't use that character!" + +        # 'tag_content' or 'tag_name' are either empty, or consist of nothing but whitespace +        elif (tag_content is not None and not tag_content) or not tag_name: +            log.warning(f"{author} tried to create a tag with a name consisting only of whitespace. " +                        "Rejecting the request.") +            embed.description = "Tags should not be empty, or filled with whitespace." + +        # 'tag_name' is a number of some kind, we don't allow that. +        elif is_number(tag_name): +            log.error("inside the is_number") +            log.warning(f"{author} tried to create a tag with a digit as its name. " +                        "Rejecting the request.") +            embed.description = "Tag names can't be numbers." + +        # 'tag_name' is longer than 127 characters +        elif len(tag_name) > 127: +            log.warning(f"{author} tried to request a tag name with over 127 characters. " +                        "Rejecting the request.") +            embed.description = "Are you insane? That's way too long!" + +        else: +            return None + +        embed.title = random.choice(Tags.FAIL_TITLES) +        return embed +      @command(name="tags()", aliases=["tags"], hidden=True)      async def info_command(self, ctx: Context):          """ @@ -96,7 +163,7 @@ class Tags:          return await ctx.invoke(self.bot.get_command("help"), "Tags")      @command(name="tags.get()", aliases=["tags.get", "tags.show()", "tags.show", "get_tag"]) -    async def get_command(self, ctx: Context, tag_name=None): +    async def get_command(self, ctx: Context, tag_name: str=None):          """          Get a list of all tags or a specified tag. @@ -135,9 +202,17 @@ class Tags:                          f"Cooldown ends in {time_left:.1f} seconds.")              return -        embed = Embed()          tags = [] +        if tag_name is not None: +            tag_name = tag_name.lower().strip() +            validation = await self.validate(ctx.author, tag_name) + +            if validation is not None: +                return await ctx.send(embed=validation) + +        embed = Embed() +        embed.colour = Colour.red()          tag_data = await self.get_tag_data(tag_name)          # If we found something, prepare that data @@ -169,14 +244,14 @@ class Tags:              if isinstance(tag_data, dict):                  log.warning(f"{ctx.author} requested the tag '{tag_name}', but it could not be found.") -                embed.description = f"Unknown tag: **{tag_name}**" +                embed.description = f"**{tag_name}** is an unknown tag name. Please check the spelling and try again."              else:                  log.warning(f"{ctx.author} requested a list of all tags, but the tags database was empty!")                  embed.description = "**There are no tags in the database!**"              if tag_name:                  embed.set_footer(text="To show a list of all tags, use bot.tags.get().") -                embed.title = "Tag not found" +                embed.title = "Tag not found."          # Paginate if this is a list of all tags          if tags: @@ -202,58 +277,33 @@ class Tags:          :param tag_content: The content of the tag.          """ -        def is_number(string): -            try: -                float(string) -            except ValueError: -                return False -            else: -                return True - -        embed = Embed() -        embed.colour = Colour.red() +        validation = await self.validate(ctx.author, tag_name, tag_content) -        # Newline in 'tag_name' -        if "\n" in tag_name: -            log.warning(f"{ctx.author} tried to put a newline in a tag name. " -                        "Rejecting the request.") -            embed.title = "Please don't do that" -            embed.description = "Don't be ridiculous. Newlines are obviously not allowed in the tag name." +        if validation is not None: +            return await ctx.send(embed=validation) -        # 'tag_name' or 'tag_content' consists of nothing but whitespace -        elif not tag_content.strip() or not tag_name.strip(): -            log.warning(f"{ctx.author} tried to create a tag with a name consisting only of whitespace. " -                        "Rejecting the request.") -            embed.title = "Please don't do that" -            embed.description = "Tags should not be empty, or filled with whitespace." +        tag_name = tag_name.lower().strip() +        tag_content = tag_content.strip() -        # 'tag_name' is a number of some kind, we don't allow that. -        elif is_number(tag_name): -            log.error("inside the is_number") -            log.warning(f"{ctx.author} tried to create a tag with a digit as its name. " -                        "Rejecting the request.") -            embed.title = "Please don't do that" -            embed.description = "Tag names can't be numbers." +        embed = Embed() +        embed.colour = Colour.red() +        tag_data = await self.post_tag_data(tag_name, tag_content) +        if tag_data.get("success"): +            log.debug(f"{ctx.author} successfully added the following tag to our database: \n" +                      f"tag_name: {tag_name}\n" +                      f"tag_content: '{tag_content}'") +            embed.colour = Colour.blurple() +            embed.title = "Tag successfully added" +            embed.description = f"**{tag_name}** added to tag database."          else: -            tag_name = tag_name.lower() -            tag_data = await self.post_tag_data(tag_name, tag_content) - -            if tag_data.get("success"): -                log.debug(f"{ctx.author} successfully added the following tag to our database: \n" -                          f"tag_name: {tag_name}\n" -                          f"tag_content: '{tag_content}'") -                embed.colour = Colour.blurple() -                embed.title = "Tag successfully added" -                embed.description = f"**{tag_name}** added to tag database." -            else: -                log.error("There was an unexpected database error when trying to add the following tag: \n" -                          f"tag_name: {tag_name}\n" -                          f"tag_content: '{tag_content}'\n" -                          f"response: {tag_data}") -                embed.title = "Database error" -                embed.description = ("There was a problem adding the data to the tags database. " -                                     "Please try again. If the problem persists, see the error logs.") +            log.error("There was an unexpected database error when trying to add the following tag: \n" +                      f"tag_name: {tag_name}\n" +                      f"tag_content: '{tag_content}'\n" +                      f"response: {tag_data}") +            embed.title = "Database error" +            embed.description = ("There was a problem adding the data to the tags database. " +                                 "Please try again. If the problem persists, see the error logs.")          return await ctx.send(embed=embed) @@ -267,9 +317,14 @@ class Tags:          :param tag_name: The name of the tag to delete.          """ +        validation = await self.validate(ctx.author, tag_name) + +        if validation is not None: +            return await ctx.send(embed=validation) + +        tag_name = tag_name.lower().strip()          embed = Embed()          embed.colour = Colour.red() -          tag_data = await self.delete_tag_data(tag_name)          if tag_data.get("success") is True: @@ -2,5 +2,5 @@  max-line-length=120  application_import_names=bot  exclude=.venv -ignore=B311,W503,E226 +ignore=B311,W503,E226,S311  import-order-style=pycharm | 
