diff options
Diffstat (limited to 'bot')
| -rw-r--r-- | bot/exts/easter/easter_riddle.py | 13 | ||||
| -rw-r--r-- | bot/exts/evergreen/githubinfo.py | 143 | ||||
| -rw-r--r-- | bot/exts/evergreen/issues.py | 38 | ||||
| -rw-r--r-- | bot/exts/evergreen/wolfram.py | 3 | ||||
| -rw-r--r-- | bot/exts/halloween/candy_collection.py | 3 | ||||
| -rw-r--r-- | bot/resources/easter/april_fools_vids.json | 16 | ||||
| -rw-r--r-- | bot/resources/evergreen/py_topics.yaml | 6 | ||||
| -rw-r--r-- | bot/resources/evergreen/starter.yaml | 20 | ||||
| -rw-r--r-- | bot/utils/decorators.py | 10 | 
9 files changed, 206 insertions, 46 deletions
| diff --git a/bot/exts/easter/easter_riddle.py b/bot/exts/easter/easter_riddle.py index 3c612eb1..a93b3745 100644 --- a/bot/exts/easter/easter_riddle.py +++ b/bot/exts/easter/easter_riddle.py @@ -7,7 +7,7 @@ from pathlib import Path  import discord  from discord.ext import commands -from bot.constants import Colours +from bot.constants import Colours, NEGATIVE_REPLIES  log = logging.getLogger(__name__) @@ -36,6 +36,17 @@ class EasterRiddle(commands.Cog):          if self.current_channel:              return await ctx.send(f"A riddle is already being solved in {self.current_channel.mention}!") +        # Don't let users start in a DM +        if not ctx.guild: +            await ctx.send( +                embed=discord.Embed( +                    title=random.choice(NEGATIVE_REPLIES), +                    description="You can't start riddles in DMs", +                    colour=discord.Colour.red() +                ) +            ) +            return +          self.current_channel = ctx.message.channel          random_question = random.choice(RIDDLE_QUESTIONS) diff --git a/bot/exts/evergreen/githubinfo.py b/bot/exts/evergreen/githubinfo.py index 2e38e3ab..c8a6b3f7 100644 --- a/bot/exts/evergreen/githubinfo.py +++ b/bot/exts/evergreen/githubinfo.py @@ -1,16 +1,19 @@  import logging  import random  from datetime import datetime -from typing import Optional +from urllib.parse import quote  import discord  from discord.ext import commands  from discord.ext.commands.cooldowns import BucketType -from bot.constants import NEGATIVE_REPLIES +from bot.constants import Colours, NEGATIVE_REPLIES +from bot.exts.utils.extensions import invoke_help_command  log = logging.getLogger(__name__) +GITHUB_API_URL = "https://api.github.com" +  class GithubInfo(commands.Cog):      """Fetches info from GitHub.""" @@ -23,27 +26,28 @@ class GithubInfo(commands.Cog):          async with self.bot.http_session.get(url) as r:              return await r.json() -    @commands.command(name='github', aliases=['gh']) -    @commands.cooldown(1, 60, BucketType.user) -    async def get_github_info(self, ctx: commands.Context, username: Optional[str]) -> None: -        """ -        Fetches a user's GitHub information. - -        Username is optional and sends the help command if not specified. -        """ -        if username is None: -            await ctx.invoke(self.bot.get_command('help'), 'github') -            ctx.command.reset_cooldown(ctx) -            return +    @commands.group(name='github', aliases=('gh', 'git')) +    @commands.cooldown(1, 10, BucketType.user) +    async def github_group(self, ctx: commands.Context) -> None: +        """Commands for finding information related to GitHub.""" +        if ctx.invoked_subcommand is None: +            await invoke_help_command(ctx) +    @github_group.command(name='user', aliases=('userinfo',)) +    async def github_user_info(self, ctx: commands.Context, username: str) -> None: +        """Fetches a user's GitHub information."""          async with ctx.typing(): -            user_data = await self.fetch_data(f"https://api.github.com/users/{username}") +            user_data = await self.fetch_data(f"{GITHUB_API_URL}/users/{username}")              # User_data will not have a message key if the user exists -            if user_data.get('message') is not None: -                await ctx.send(embed=discord.Embed(title=random.choice(NEGATIVE_REPLIES), -                                                   description=f"The profile for `{username}` was not found.", -                                                   colour=discord.Colour.red())) +            if "message" in user_data: +                embed = discord.Embed( +                    title=random.choice(NEGATIVE_REPLIES), +                    description=f"The profile for `{username}` was not found.", +                    colour=Colours.soft_red +                ) + +                await ctx.send(embed=embed)                  return              org_data = await self.fetch_data(user_data['organizations_url']) @@ -63,7 +67,7 @@ class GithubInfo(commands.Cog):              embed = discord.Embed(                  title=f"`{user_data['login']}`'s GitHub profile info",                  description=f"```{user_data['bio']}```\n" if user_data['bio'] is not None else "", -                colour=0x7289da, +                colour=discord.Colour.blurple(),                  url=user_data['html_url'],                  timestamp=datetime.strptime(user_data['created_at'], "%Y-%m-%dT%H:%M:%SZ")              ) @@ -72,26 +76,99 @@ class GithubInfo(commands.Cog):              if user_data['type'] == "User": -                embed.add_field(name="Followers", -                                value=f"[{user_data['followers']}]({user_data['html_url']}?tab=followers)") -                embed.add_field(name="\u200b", value="\u200b") -                embed.add_field(name="Following", -                                value=f"[{user_data['following']}]({user_data['html_url']}?tab=following)") - -            embed.add_field(name="Public repos", -                            value=f"[{user_data['public_repos']}]({user_data['html_url']}?tab=repositories)") -            embed.add_field(name="\u200b", value="\u200b") +                embed.add_field( +                    name="Followers", +                    value=f"[{user_data['followers']}]({user_data['html_url']}?tab=followers)" +                ) +                embed.add_field( +                    name="Following", +                    value=f"[{user_data['following']}]({user_data['html_url']}?tab=following)" +                ) + +            embed.add_field( +                name="Public repos", +                value=f"[{user_data['public_repos']}]({user_data['html_url']}?tab=repositories)" +            )              if user_data['type'] == "User": -                embed.add_field(name="Gists", value=f"[{gists}](https://gist.github.com/{username})") +                embed.add_field(name="Gists", value=f"[{gists}](https://gist.github.com/{quote(username, safe='')})") -                embed.add_field(name=f"Organization{'s' if len(orgs)!=1 else ''}", -                                value=orgs_to_add if orgs else "No organizations") -                embed.add_field(name="\u200b", value="\u200b") +                embed.add_field( +                    name=f"Organization{'s' if len(orgs)!=1 else ''}", +                    value=orgs_to_add if orgs else "No organizations" +                )              embed.add_field(name="Website", value=blog)          await ctx.send(embed=embed) +    @github_group.command(name='repository', aliases=('repo',)) +    async def github_repo_info(self, ctx: commands.Context, *repo: str) -> None: +        """ +        Fetches a repositories' GitHub information. + +        The repository should look like `user/reponame` or `user reponame`. +        """ +        repo = '/'.join(repo) +        if repo.count('/') != 1: +            embed = discord.Embed( +                title=random.choice(NEGATIVE_REPLIES), +                description="The repository should look like `user/reponame` or `user reponame`.", +                colour=Colours.soft_red +            ) + +            await ctx.send(embed=embed) +            return + +        async with ctx.typing(): +            repo_data = await self.fetch_data(f"{GITHUB_API_URL}/repos/{quote(repo)}") + +            # There won't be a message key if this repo exists +            if "message" in repo_data: +                embed = discord.Embed( +                    title=random.choice(NEGATIVE_REPLIES), +                    description="The requested repository was not found.", +                    colour=Colours.soft_red +                ) + +                await ctx.send(embed=embed) +                return + +        embed = discord.Embed( +            title=repo_data['name'], +            description=repo_data["description"], +            colour=discord.Colour.blurple(), +            url=repo_data['html_url'] +        ) + +        # If it's a fork, then it will have a parent key +        try: +            parent = repo_data["parent"] +            embed.description += f"\n\nForked from [{parent['full_name']}]({parent['html_url']})" +        except KeyError: +            log.debug("Repository is not a fork.") + +        repo_owner = repo_data['owner'] + +        embed.set_author( +            name=repo_owner["login"], +            url=repo_owner["html_url"], +            icon_url=repo_owner["avatar_url"] +        ) + +        repo_created_at = datetime.strptime(repo_data['created_at'], "%Y-%m-%dT%H:%M:%SZ").strftime("%d/%m/%Y") +        last_pushed = datetime.strptime(repo_data['pushed_at'], "%Y-%m-%dT%H:%M:%SZ").strftime("%d/%m/%Y at %H:%M") + +        embed.set_footer( +            text=( +                f"{repo_data['forks_count']} ⑂ " +                f"• {repo_data['stargazers_count']} ⭐ " +                f"• Created At {repo_created_at} " +                f"• Last Commit {last_pushed}" +            ) +        ) + +        await ctx.send(embed=embed) +  def setup(bot: commands.Bot) -> None:      """Adding the cog to the bot.""" diff --git a/bot/exts/evergreen/issues.py b/bot/exts/evergreen/issues.py index bbcbf611..4a73d20b 100644 --- a/bot/exts/evergreen/issues.py +++ b/bot/exts/evergreen/issues.py @@ -7,7 +7,16 @@ from enum import Enum  import discord  from discord.ext import commands, tasks -from bot.constants import Categories, Channels, Colours, ERROR_REPLIES, Emojis, Tokens, WHITELISTED_CHANNELS +from bot.constants import ( +    Categories, +    Channels, +    Colours, +    ERROR_REPLIES, +    Emojis, +    NEGATIVE_REPLIES, +    Tokens, +    WHITELISTED_CHANNELS +)  log = logging.getLogger(__name__) @@ -150,10 +159,20 @@ class Issues(commands.Cog):              user: str = "python-discord"      ) -> None:          """Command to retrieve issue(s) from a GitHub repository.""" -        if not( +        if not ctx.guild or not(              ctx.channel.category.id in WHITELISTED_CATEGORIES              or ctx.channel.id in WHITELISTED_CHANNELS          ): +            await ctx.send( +                embed=discord.Embed( +                    title=random.choice(NEGATIVE_REPLIES), +                    description=( +                        "You can't run this command in this channel. " +                        f"Try again in <#{Channels.community_bot_commands}>" +                    ), +                    colour=discord.Colour.red() +                ) +            )              return          result = await self.fetch_issues(set(numbers), repository, user) @@ -180,7 +199,8 @@ class Issues(commands.Cog):      @commands.Cog.listener()      async def on_message(self, message: discord.Message) -> None:          """Command to retrieve issue(s) from a GitHub repository using automatic linking if matching <repo>#<issue>.""" -        if not( +        # Ignore messages not in whitelisted categories / channels, only when in guild. +        if message.guild and not (              message.channel.category.id in WHITELISTED_CATEGORIES              or message.channel.id in WHITELISTED_CHANNELS_ON_MESSAGE          ): @@ -190,6 +210,18 @@ class Issues(commands.Cog):          links = []          if message_repo_issue_map: +            if not message.guild: +                await message.channel.send( +                    embed=discord.Embed( +                        title=random.choice(NEGATIVE_REPLIES), +                        description=( +                            "You can't retreive issues from DMs. " +                            f"Try again in <#{Channels.community_bot_commands}>" +                        ), +                        colour=discord.Colour.red() +                    ) +                ) +                return              for repo_issue in message_repo_issue_map:                  if not self.check_in_block(message, " ".join(repo_issue)):                      result = await self.fetch_issues({repo_issue[1]}, repo_issue[0], "python-discord") diff --git a/bot/exts/evergreen/wolfram.py b/bot/exts/evergreen/wolfram.py index 437d9e1a..14ec1041 100644 --- a/bot/exts/evergreen/wolfram.py +++ b/bot/exts/evergreen/wolfram.py @@ -62,7 +62,8 @@ def custom_cooldown(*ignore: List[int]) -> Callable:              # if the invoked command is help we don't want to increase the ratelimits since it's not actually              # invoking the command/making a request, so instead just check if the user/guild are on cooldown.              guild_cooldown = not guildcd.get_bucket(ctx.message).get_tokens() == 0  # if guild is on cooldown -            if not any(r.id in ignore for r in ctx.author.roles):  # check user bucket if user is not ignored +            # check the message is in a guild, and check user bucket if user is not ignored +            if ctx.guild and not any(r.id in ignore for r in ctx.author.roles):                  return guild_cooldown and not usercd.get_bucket(ctx.message).get_tokens() == 0              return guild_cooldown diff --git a/bot/exts/halloween/candy_collection.py b/bot/exts/halloween/candy_collection.py index 0cb37ecd..40e21f40 100644 --- a/bot/exts/halloween/candy_collection.py +++ b/bot/exts/halloween/candy_collection.py @@ -47,6 +47,9 @@ class CandyCollection(commands.Cog):      @commands.Cog.listener()      async def on_message(self, message: discord.Message) -> None:          """Randomly adds candy or skull reaction to non-bot messages in the Event channel.""" +        # Ignore messages in DMs +        if not message.guild: +            return          # make sure its a human message          if message.author.bot:              return diff --git a/bot/resources/easter/april_fools_vids.json b/bot/resources/easter/april_fools_vids.json index 5f0ba06e..b2cbd07b 100644 --- a/bot/resources/easter/april_fools_vids.json +++ b/bot/resources/easter/april_fools_vids.json @@ -17,10 +17,6 @@        "link": "https://youtu.be/3MA6_21nka8"      },      { -      "title": "Introducing Google Gnome", -      "link": "https://youtu.be/vNOllWX-2aE" -    }, -    {        "title": "Introducing Google Wind",        "link": "https://youtu.be/QAwL0O5nXe0"      }, @@ -119,6 +115,18 @@      {        "title": "Introducing Gmail Motion",        "link": "https://youtu.be/Bu927_ul_X0" +    }, +    { +      "title": "Introducing GeForce GTX G-Assist", +      "link": "https://youtu.be/smM-Wdk2RLQ" +    }, +    { +      "title": "The Hovering Mouse - Project McFly | Razer", +      "link": "https://youtu.be/IlCx5gjAmqI" +    }, +    { +      "title": "Be the Machine | Project Venom v2", +      "link": "https://youtu.be/j8UJE7DoyJ8"      }    ] diff --git a/bot/resources/evergreen/py_topics.yaml b/bot/resources/evergreen/py_topics.yaml index f3b2eaa3..6b7e0206 100644 --- a/bot/resources/evergreen/py_topics.yaml +++ b/bot/resources/evergreen/py_topics.yaml @@ -69,7 +69,11 @@  # game-development  660625198390837248: -    - +    - What is your favorite game mechanic? +    - What is your favorite framework and why? +    - What games do you know that were written in Python? +    - What books or tutorials would you recommend for game-development beginners? +    - What made you start developing games?  # microcontrollers  545603026732318730: diff --git a/bot/resources/evergreen/starter.yaml b/bot/resources/evergreen/starter.yaml index 949220f9..6b0de0ef 100644 --- a/bot/resources/evergreen/starter.yaml +++ b/bot/resources/evergreen/starter.yaml @@ -6,7 +6,6 @@  - "What is better: Milk, Dark or White chocolate?"  - What is your favourite holiday?  - If you could have any superpower, what would it be? -- Name one thing you like about a person to your right.  - If you could be anyone else for one day, who would it be?  - What Easter tradition do you enjoy most?  - What is the best gift you've been given? @@ -31,3 +30,22 @@  - What is your favorite TV show?  - What is your favorite media genre?  - How many years have you spent coding? +- What book do you highly recommend everyone to read? +- What websites do you use daily to keep yourself up to date with the industry? +- What made you want to join this Discord server? +- How are you? +- What is the best advice you have ever gotten in regards to programming/software? +- What is the most satisfying thing you've done in your life? +- Who is your favorite music composer/producer/singer? +- What is your favorite song? +- What is your favorite video game? +- What are your hobbies other than programming? +- Who is your favorite Writer? +- What is your favorite movie? +- What is your favorite sport? +- What is your favorite fruit? +- What is your favorite juice? +- What is the best scenery you've ever seen? +- What artistic talents do you have? +- What is the tallest building you've entered? +- What is the oldest computer you've ever used? diff --git a/bot/utils/decorators.py b/bot/utils/decorators.py index c12a15ff..60066dc4 100644 --- a/bot/utils/decorators.py +++ b/bot/utils/decorators.py @@ -11,7 +11,7 @@ from discord import Colour, Embed  from discord.ext import commands  from discord.ext.commands import CheckFailure, Command, Context -from bot.constants import ERROR_REPLIES, Month +from bot.constants import Channels, ERROR_REPLIES, Month, WHITELISTED_CHANNELS  from bot.utils import human_months, resolve_current_month  from bot.utils.checks import in_whitelist_check @@ -253,6 +253,12 @@ def whitelist_check(**default_kwargs: t.Container[int]) -> t.Callable[[Context],          channels = set(kwargs.get("channels") or {})          categories = kwargs.get("categories") +        # Only output override channels + community_bot_commands +        if channels: +            default_whitelist_channels = set(WHITELISTED_CHANNELS) +            default_whitelist_channels.discard(Channels.community_bot_commands) +            channels.difference_update(default_whitelist_channels) +          # Add all whitelisted category channels          if categories:              for category_id in categories: @@ -260,7 +266,7 @@ def whitelist_check(**default_kwargs: t.Container[int]) -> t.Callable[[Context],                  if category is None:                      continue -                [channels.add(channel.id) for channel in category.text_channels] +                channels.update(channel.id for channel in category.text_channels)          if channels:              channels_str = ', '.join(f"<#{c_id}>" for c_id in channels) | 
