From 019c2cea32ae4fcc8a257e7ac57ec223cd6ea788 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 7 Apr 2020 11:02:57 +0300 Subject: (TicTacToe): Created initial empty cog with loading. --- bot/exts/evergreen/tic_tac_toe.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 bot/exts/evergreen/tic_tac_toe.py (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py new file mode 100644 index 00000000..d4c95728 --- /dev/null +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -0,0 +1,15 @@ +from discord.ext.commands import Cog + +from bot.bot import SeasonalBot + + +class TicTacToe(Cog): + """TicTacToe cog contains tic-tac-toe game commands.""" + + def __init__(self, bot: SeasonalBot): + self.bot = bot + + +def setup(bot: SeasonalBot) -> None: + """Load TicTacToe Cog.""" + bot.add_cog(TicTacToe(bot)) -- cgit v1.2.3 From b6dc1207fd63564bee9814ca46a955c1067fe5db Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 7 Apr 2020 11:06:48 +0300 Subject: (TicTacToe): Created `Player` class --- bot/exts/evergreen/tic_tac_toe.py | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index d4c95728..1927e021 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -1,8 +1,16 @@ +import discord from discord.ext.commands import Cog from bot.bot import SeasonalBot +class Player: + """Class that contains information about player and functions that interact with player.""" + + def __init__(self, user: discord.User): + self.user = user + + class TicTacToe(Cog): """TicTacToe cog contains tic-tac-toe game commands.""" -- cgit v1.2.3 From 7d5103c157fa36ba7cc75fa67a0ee062633b4148 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 7 Apr 2020 11:08:57 +0300 Subject: (TicTacToe): Created `Game` class --- bot/exts/evergreen/tic_tac_toe.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index 1927e021..98d793ba 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -1,5 +1,7 @@ +import typing as t + import discord -from discord.ext.commands import Cog +from discord.ext.commands import Cog, Context from bot.bot import SeasonalBot @@ -11,6 +13,15 @@ class Player: self.user = user +class Game: + """Class that contains information and functions about Tic Tac Toe game.""" + + def __init__(self, channel: discord.TextChannel, players: t.List[discord.User], ctx: Context): + self.channel = channel + self.players = players + self.ctx = ctx + + class TicTacToe(Cog): """TicTacToe cog contains tic-tac-toe game commands.""" -- cgit v1.2.3 From 103ddfe12af937c50ece9bd651b5d4da8cb29079 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 7 Apr 2020 11:48:34 +0300 Subject: (TicTacToe): Added `ctx` variable to `Player` class. --- bot/exts/evergreen/tic_tac_toe.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index 98d793ba..376cb3e9 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -9,8 +9,9 @@ from bot.bot import SeasonalBot class Player: """Class that contains information about player and functions that interact with player.""" - def __init__(self, user: discord.User): + def __init__(self, user: discord.User, ctx: Context): self.user = user + self.ctx = ctx class Game: -- cgit v1.2.3 From 3362619c919b2094994439efa0dc0564d82594f0 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 7 Apr 2020 11:49:33 +0300 Subject: (TicTacToe): Replaced `discord.User` with `Player` in `Game` class signature. --- bot/exts/evergreen/tic_tac_toe.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index 376cb3e9..2e21b43a 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -17,7 +17,7 @@ class Player: class Game: """Class that contains information and functions about Tic Tac Toe game.""" - def __init__(self, channel: discord.TextChannel, players: t.List[discord.User], ctx: Context): + def __init__(self, channel: discord.TextChannel, players: t.List[Player], ctx: Context): self.channel = channel self.players = players self.ctx = ctx -- cgit v1.2.3 From 04fe88be9b105522aec5185ab771a73c9ea1a818 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 7 Apr 2020 11:51:19 +0300 Subject: (TicTacToe): Added new player-about variables to `Game` class. --- bot/exts/evergreen/tic_tac_toe.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index 2e21b43a..0fa1902b 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -22,6 +22,12 @@ class Game: self.players = players self.ctx = ctx + self.current = self.players[0] + self.next = self.players[1] + + self.winner: t.Optional[Player] = None + self.loser: t.Optional[Player] = None + class TicTacToe(Cog): """TicTacToe cog contains tic-tac-toe game commands.""" -- cgit v1.2.3 From 83d9173cdcd8671dedf5400dde81caac21e37634 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 7 Apr 2020 11:57:13 +0300 Subject: (Constants, TicTacToe): Added number emojis that will be shown in board and in reactions. --- bot/constants.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'bot') diff --git a/bot/constants.py b/bot/constants.py index ca9bb94a..0135124b 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -118,6 +118,19 @@ class Emojis: pull_request_closed = "<:PRClosed:629695470519713818>" merge = "<:PRMerged:629695470570176522>" + # TicTacToe Emojis + number_emojis = { + 1: "\u0031", + 2: "\u0032", + 3: "\u0033", + 4: "\u0034", + 5: "\u0035", + 6: "\u0036", + 7: "\u0037", + 8: "\u0038", + 9: "\u0039" + } + class Hacktoberfest(NamedTuple): voice_id = 514420006474219521 -- cgit v1.2.3 From 1abec1772f140f886b84fb43c394527553cb271a Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 7 Apr 2020 11:59:12 +0300 Subject: (Constants, TicTacToe): Added confirmation and declining emojis. --- bot/constants.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'bot') diff --git a/bot/constants.py b/bot/constants.py index 0135124b..a23c6bcc 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -130,6 +130,8 @@ class Emojis: 8: "\u0038", 9: "\u0039" } + confirmation = "\u2705" + decline = "\u274c" class Hacktoberfest(NamedTuple): -- cgit v1.2.3 From fb9523b9c5e93ff30cdc58ac451e807da323c8b4 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 7 Apr 2020 12:01:26 +0300 Subject: (Constants, TicTacToe): Added X and O emojis. --- bot/constants.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'bot') diff --git a/bot/constants.py b/bot/constants.py index a23c6bcc..d43cf4d3 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -132,6 +132,8 @@ class Emojis: } confirmation = "\u2705" decline = "\u274c" + x = "\U0001f1fd" + o = "\U0001f1f4" class Hacktoberfest(NamedTuple): -- cgit v1.2.3 From 3d92f7e907fcee767c1428a52bb503314b8f6b19 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 7 Apr 2020 14:14:14 +0300 Subject: (TicTacToe): Added `get_confirmation` function to `Game` class to make sure that opponent want to play. --- bot/exts/evergreen/tic_tac_toe.py | 41 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index 0fa1902b..7d82e084 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -1,9 +1,16 @@ +import asyncio import typing as t import discord from discord.ext.commands import Cog, Context from bot.bot import SeasonalBot +from bot.constants import Emojis + +CONFIRMATION_MESSAGE = ( + "{opponent}, {requester} want to play Tic-Tac-Toe against you. React to this message with " + f"{Emojis.confirmation} to accept or with {Emojis.decline} to decline." +) class Player: @@ -28,6 +35,40 @@ class Game: self.winner: t.Optional[Player] = None self.loser: t.Optional[Player] = None + async def get_confirmation(self) -> t.Tuple[bool, t.Optional[str]]: + """Ask does user want to play TicTacToe against requester. First player is always requester.""" + confirm_message = await self.ctx.send( + CONFIRMATION_MESSAGE.format( + opponent=self.players[1].user.mention, + requester=self.players[0].user.mention + ) + ) + await confirm_message.add_reaction(Emojis.confirmation) + await confirm_message.add_reaction(Emojis.decline) + + def confirm_check(reaction: discord.Reaction, user: discord.User) -> bool: + return ( + reaction.emoji in (Emojis.confirmation, Emojis.decline) + and reaction.message.id == confirm_message.id + and user == self.players[1].user + ) + + try: + reaction, user = await self.ctx.bot.wait_for( + "reaction_add", + timeout=60.0, + check=confirm_check + ) + except asyncio.TimeoutError: + await confirm_message.delete() + return False, "Running out of time... Cancelled game." + + await confirm_message.delete() + if reaction.emoji == Emojis.confirmation: + return True, None + else: + return False, "User declined" + class TicTacToe(Cog): """TicTacToe cog contains tic-tac-toe game commands.""" -- cgit v1.2.3 From cab121e93829258251154c0f00b1b9d8f5dca2e4 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 7 Apr 2020 14:17:35 +0300 Subject: (TicTacToe): Created helper function `add_reactions` to `Game` class to add all number reactions to message. --- bot/exts/evergreen/tic_tac_toe.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index 7d82e084..24021842 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -69,6 +69,11 @@ class Game: else: return False, "User declined" + async def add_reactions(self, msg: discord.Message) -> None: + """Add number emojis to message.""" + for nr in Emojis.number_emojis: + await msg.add_reaction(nr) + class TicTacToe(Cog): """TicTacToe cog contains tic-tac-toe game commands.""" -- cgit v1.2.3 From fa5ba85d3c9da611c10412cc2ee75eeff3a434f9 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 7 Apr 2020 14:18:33 +0300 Subject: (TicTacToe): Added new variable `games` to `TicTacToe` cog. --- bot/exts/evergreen/tic_tac_toe.py | 1 + 1 file changed, 1 insertion(+) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index 24021842..28f48e11 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -80,6 +80,7 @@ class TicTacToe(Cog): def __init__(self, bot: SeasonalBot): self.bot = bot + self.games: t.List[Game] = [] def setup(bot: SeasonalBot) -> None: -- cgit v1.2.3 From 88762008d4fc36744f1dc5507a90015a37a0a9eb Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 7 Apr 2020 14:39:01 +0300 Subject: (TicTacToe): Created check `is_channel_free`. --- bot/exts/evergreen/tic_tac_toe.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index 28f48e11..301cb9ff 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -2,7 +2,7 @@ import asyncio import typing as t import discord -from discord.ext.commands import Cog, Context +from discord.ext.commands import Cog, Context, check from bot.bot import SeasonalBot from bot.constants import Emojis @@ -82,6 +82,13 @@ class TicTacToe(Cog): self.bot = bot self.games: t.List[Game] = [] + @staticmethod + def is_channel_free() -> t.Callable: + """Check is channel where command will be invoked free.""" + async def predicate(ctx: Context) -> bool: + return all(game.channel != ctx.channel for game in ctx.cog.games) + return check(predicate) + def setup(bot: SeasonalBot) -> None: """Load TicTacToe Cog.""" -- cgit v1.2.3 From 88a121db968de07880037ffcc05462ef65cfaa2e Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 7 Apr 2020 17:02:16 +0300 Subject: (TicTacToe): Created check `is_requester_free`. --- bot/exts/evergreen/tic_tac_toe.py | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index 301cb9ff..90f916ef 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -89,6 +89,13 @@ class TicTacToe(Cog): return all(game.channel != ctx.channel for game in ctx.cog.games) return check(predicate) + @staticmethod + def is_requester_free() -> t.Callable: + """Check is requester not already in any game.""" + async def predicate(ctx: Context) -> bool: + return all(ctx.author not in (player.user for player in game.players) for game in ctx.cog.games) + return check(predicate) + def setup(bot: SeasonalBot) -> None: """Load TicTacToe Cog.""" -- cgit v1.2.3 From 4a97fcd91d610da69d9dd4b75ca2bf80a094ae61 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 7 Apr 2020 17:05:38 +0300 Subject: (TicTacToe): Created new class variable `over` to `Game`, added over check to cog checks. --- bot/exts/evergreen/tic_tac_toe.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index 90f916ef..2795f94a 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -34,6 +34,7 @@ class Game: self.winner: t.Optional[Player] = None self.loser: t.Optional[Player] = None + self.over = False async def get_confirmation(self) -> t.Tuple[bool, t.Optional[str]]: """Ask does user want to play TicTacToe against requester. First player is always requester.""" @@ -60,6 +61,7 @@ class Game: check=confirm_check ) except asyncio.TimeoutError: + self.over = True await confirm_message.delete() return False, "Running out of time... Cancelled game." @@ -67,6 +69,7 @@ class Game: if reaction.emoji == Emojis.confirmation: return True, None else: + self.over = True return False, "User declined" async def add_reactions(self, msg: discord.Message) -> None: @@ -86,14 +89,16 @@ class TicTacToe(Cog): def is_channel_free() -> t.Callable: """Check is channel where command will be invoked free.""" async def predicate(ctx: Context) -> bool: - return all(game.channel != ctx.channel for game in ctx.cog.games) + return all(game.channel != ctx.channel for game in ctx.cog.games if not game.over) return check(predicate) @staticmethod def is_requester_free() -> t.Callable: """Check is requester not already in any game.""" async def predicate(ctx: Context) -> bool: - return all(ctx.author not in (player.user for player in game.players) for game in ctx.cog.games) + return all( + ctx.author not in (player.user for player in game.players) for game in ctx.cog.games if not game.over + ) return check(predicate) -- cgit v1.2.3 From 85750308db80a56b539004d935c3032e96c4947f Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 7 Apr 2020 17:16:08 +0300 Subject: (TicTacToe): Moved checks to outside of class, created initial tic tac toe command. --- bot/exts/evergreen/tic_tac_toe.py | 46 +++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 16 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index 2795f94a..1a906535 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -2,7 +2,7 @@ import asyncio import typing as t import discord -from discord.ext.commands import Cog, Context, check +from discord.ext.commands import Cog, Context, check, command, guild_only from bot.bot import SeasonalBot from bot.constants import Emojis @@ -78,6 +78,22 @@ class Game: await msg.add_reaction(nr) +def is_channel_free() -> t.Callable: + """Check is channel where command will be invoked free.""" + async def predicate(ctx: Context) -> bool: + return all(game.channel != ctx.channel for game in ctx.cog.games if not game.over) + return check(predicate) + + +def is_requester_free() -> t.Callable: + """Check is requester not already in any game.""" + async def predicate(ctx: Context) -> bool: + return all( + ctx.author not in (player.user for player in game.players) for game in ctx.cog.games if not game.over + ) + return check(predicate) + + class TicTacToe(Cog): """TicTacToe cog contains tic-tac-toe game commands.""" @@ -85,21 +101,19 @@ class TicTacToe(Cog): self.bot = bot self.games: t.List[Game] = [] - @staticmethod - def is_channel_free() -> t.Callable: - """Check is channel where command will be invoked free.""" - async def predicate(ctx: Context) -> bool: - return all(game.channel != ctx.channel for game in ctx.cog.games if not game.over) - return check(predicate) - - @staticmethod - def is_requester_free() -> t.Callable: - """Check is requester not already in any game.""" - async def predicate(ctx: Context) -> bool: - return all( - ctx.author not in (player.user for player in game.players) for game in ctx.cog.games if not game.over - ) - return check(predicate) + @guild_only() + @is_channel_free() + @is_requester_free() + @command(name="tictactoe", aliases=("ttt",)) + async def tic_tac_toe(self, ctx: Context, opponent: discord.User) -> None: + """Tic Tac Toe game. Play agains friends. Use reactions to add your mark to field.""" + game = Game( + ctx.channel, + [Player(ctx.author, ctx), Player(opponent, ctx)], + ctx + ) + self.games.append(game) + await game.get_confirmation() def setup(bot: SeasonalBot) -> None: -- cgit v1.2.3 From 7a7385bf222c24f78356ea46331ae5d4abddb65a Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 7 Apr 2020 19:33:05 +0300 Subject: (Constants, TicTacToe): Fixed number emojis contants, created helper function `send_board` to `Game` class. --- bot/constants.py | 18 +++++++++--------- bot/exts/evergreen/tic_tac_toe.py | 23 +++++++++++++++++++++-- 2 files changed, 30 insertions(+), 11 deletions(-) (limited to 'bot') diff --git a/bot/constants.py b/bot/constants.py index d43cf4d3..a8dd03e6 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -120,15 +120,15 @@ class Emojis: # TicTacToe Emojis number_emojis = { - 1: "\u0031", - 2: "\u0032", - 3: "\u0033", - 4: "\u0034", - 5: "\u0035", - 6: "\u0036", - 7: "\u0037", - 8: "\u0038", - 9: "\u0039" + 1: "\u0031\ufe0f\u20e3", + 2: "\u0032\ufe0f\u20e3", + 3: "\u0033\ufe0f\u20e3", + 4: "\u0034\ufe0f\u20e3", + 5: "\u0035\ufe0f\u20e3", + 6: "\u0036\ufe0f\u20e3", + 7: "\u0037\ufe0f\u20e3", + 8: "\u0038\ufe0f\u20e3", + 9: "\u0039\ufe0f\u20e3" } confirmation = "\u2705" decline = "\u274c" diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index 1a906535..55bbb7be 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -28,6 +28,11 @@ class Game: self.channel = channel self.players = players self.ctx = ctx + self.board = [ + [Emojis.number_emojis[1], Emojis.number_emojis[2], Emojis.number_emojis[3]], + [Emojis.number_emojis[4], Emojis.number_emojis[5], Emojis.number_emojis[6]], + [Emojis.number_emojis[7], Emojis.number_emojis[8], Emojis.number_emojis[9]] + ] self.current = self.players[0] self.next = self.players[1] @@ -74,9 +79,18 @@ class Game: async def add_reactions(self, msg: discord.Message) -> None: """Add number emojis to message.""" - for nr in Emojis.number_emojis: + for nr in Emojis.number_emojis.values(): await msg.add_reaction(nr) + async def send_board(self) -> discord.Message: + """Send board and return it's message.""" + msg = "" + for line in self.board: + msg += " ".join(line) + msg += "\n" + message = await self.ctx.send(msg) + return message + def is_channel_free() -> t.Callable: """Check is channel where command will be invoked free.""" @@ -113,7 +127,12 @@ class TicTacToe(Cog): ctx ) self.games.append(game) - await game.get_confirmation() + confirmed, msg = await game.get_confirmation() + + if not confirmed: + if msg: + await ctx.send(msg) + return def setup(bot: SeasonalBot) -> None: -- cgit v1.2.3 From 0af8726612f53ce6e52fbd636e0709c06d78415d Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 7 Apr 2020 19:36:32 +0300 Subject: (TicTacToe): Added check is opponent free when request playing. --- bot/exts/evergreen/tic_tac_toe.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index 55bbb7be..01417f25 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -121,6 +121,11 @@ class TicTacToe(Cog): @command(name="tictactoe", aliases=("ttt",)) async def tic_tac_toe(self, ctx: Context, opponent: discord.User) -> None: """Tic Tac Toe game. Play agains friends. Use reactions to add your mark to field.""" + if not all( + opponent not in (player.user for player in g.players) for g in ctx.cog.games if not g.over + ): + await ctx.send("Opponent is already in game.") + return game = Game( ctx.channel, [Player(ctx.author, ctx), Player(opponent, ctx)], -- cgit v1.2.3 From 89e963b08a6348213d0585f17de4e18441426eb4 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 7 Apr 2020 19:37:53 +0300 Subject: (TicTacToe): Added `symbol` to `Player` class. --- bot/exts/evergreen/tic_tac_toe.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index 01417f25..bb8f8dac 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -16,9 +16,10 @@ CONFIRMATION_MESSAGE = ( class Player: """Class that contains information about player and functions that interact with player.""" - def __init__(self, user: discord.User, ctx: Context): + def __init__(self, user: discord.User, ctx: Context, symbol: str): self.user = user self.ctx = ctx + self.symbol = symbol class Game: -- cgit v1.2.3 From 65c496169259c79f537d8aa38d21eb32feb817c2 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Tue, 7 Apr 2020 19:38:48 +0300 Subject: (TicTacToe): Added `symbol` to player class creation in `tictactoe` command. --- bot/exts/evergreen/tic_tac_toe.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index bb8f8dac..1873216d 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -129,7 +129,7 @@ class TicTacToe(Cog): return game = Game( ctx.channel, - [Player(ctx.author, ctx), Player(opponent, ctx)], + [Player(ctx.author, ctx, Emojis.x), Player(opponent, ctx, Emojis.o)], ctx ) self.games.append(game) -- cgit v1.2.3 From 7c930b7bc003fecd42aef58384d33708aa1d4bfa Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Thu, 9 Apr 2020 13:28:11 +0300 Subject: (TicTacToe): Removed unnecessary variable creation in `Game.send_board`. --- bot/exts/evergreen/tic_tac_toe.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index 1873216d..ea503e83 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -89,8 +89,7 @@ class Game: for line in self.board: msg += " ".join(line) msg += "\n" - message = await self.ctx.send(msg) - return message + return await self.ctx.send(msg) def is_channel_free() -> t.Callable: -- cgit v1.2.3 From b4fa0b421b7949f0aea37e1eede68c0ba2432918 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Thu, 9 Apr 2020 13:36:01 +0300 Subject: (TicTacToe): Created function `Game.play`. --- bot/exts/evergreen/tic_tac_toe.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index ea503e83..260c8c2f 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -91,6 +91,12 @@ class Game: msg += "\n" return await self.ctx.send(msg) + async def play(self) -> None: + """Start and handle game.""" + await self.ctx.send("It's time for game! Let's begin.") + board = await self.send_board() + await self.add_reactions(board) + def is_channel_free() -> t.Callable: """Check is channel where command will be invoked free.""" -- cgit v1.2.3 From ed7bbbcb635dcc6bf5e4028cc6fd1bc4abfe97a2 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Thu, 9 Apr 2020 17:14:23 +0300 Subject: (TicTacToe): Redesigned board system, applied it's changes + created new function to `Player` class: `get_move`. --- bot/exts/evergreen/tic_tac_toe.py | 47 ++++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 8 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index 260c8c2f..1df4571b 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -21,6 +21,27 @@ class Player: self.ctx = ctx self.symbol = symbol + async def get_move(self, board: t.Dict[int, str], msg: discord.Message) -> t.Tuple[bool, t.Optional[int]]: + """ + Get move from user. + + Return is timeout reached and position of field what user will fill when timeout don't reach. + """ + def check_for_move(r: discord.Reaction, u: discord.User) -> bool: + return ( + u.id == self.user.id + and msg.id == r.message.id + and r.emoji in board.values() + and r.emoji in Emojis.number_emojis.values() + ) + + try: + react, = await self.ctx.bot.wait_for('reaction_add', timeout=120.0, check=check_for_move) + except asyncio.TimeoutError: + return True, None + else: + return False, Emojis.number_emojis.keys()[Emojis.number_emojis.values().index(react.emoji)] + class Game: """Class that contains information and functions about Tic Tac Toe game.""" @@ -29,11 +50,17 @@ class Game: self.channel = channel self.players = players self.ctx = ctx - self.board = [ - [Emojis.number_emojis[1], Emojis.number_emojis[2], Emojis.number_emojis[3]], - [Emojis.number_emojis[4], Emojis.number_emojis[5], Emojis.number_emojis[6]], - [Emojis.number_emojis[7], Emojis.number_emojis[8], Emojis.number_emojis[9]] - ] + self.board = { + 1: Emojis.number_emojis[1], + 2: Emojis.number_emojis[2], + 3: Emojis.number_emojis[3], + 4: Emojis.number_emojis[4], + 5: Emojis.number_emojis[5], + 6: Emojis.number_emojis[6], + 7: Emojis.number_emojis[7], + 8: Emojis.number_emojis[8], + 9: Emojis.number_emojis[9] + } self.current = self.players[0] self.next = self.players[1] @@ -86,9 +113,13 @@ class Game: async def send_board(self) -> discord.Message: """Send board and return it's message.""" msg = "" - for line in self.board: - msg += " ".join(line) - msg += "\n" + c = 0 + for line in self.board.values(): + msg += f"{line} " + c += 1 + if c == 3: + msg += "\n" + c = 0 return await self.ctx.send(msg) async def play(self) -> None: -- cgit v1.2.3 From c62669579d566e0c396bccf9798344d74b77aefa Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Thu, 9 Apr 2020 18:55:14 +0300 Subject: (TicTacToe): Created `edit_board` function to `Game`, made fixes to `Player.get_move`, implemented `Game.play` functionality. --- bot/exts/evergreen/tic_tac_toe.py | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index 1df4571b..b9e44220 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -36,11 +36,11 @@ class Player: ) try: - react, = await self.ctx.bot.wait_for('reaction_add', timeout=120.0, check=check_for_move) + react, _ = await self.ctx.bot.wait_for('reaction_add', timeout=120.0, check=check_for_move) except asyncio.TimeoutError: return True, None else: - return False, Emojis.number_emojis.keys()[Emojis.number_emojis.values().index(react.emoji)] + return False, list(Emojis.number_emojis.keys())[list(Emojis.number_emojis.values()).index(react.emoji)] class Game: @@ -122,12 +122,38 @@ class Game: c = 0 return await self.ctx.send(msg) + async def edit_board(self, message: discord.Message) -> None: + """Edit Tic Tac Toe game board in message.""" + msg = "" + c = 0 + for line in self.board.values(): + msg += f"{line} " + c += 1 + if c == 3: + msg += "\n" + c = 0 + await message.edit(content=msg) + async def play(self) -> None: """Start and handle game.""" await self.ctx.send("It's time for game! Let's begin.") board = await self.send_board() await self.add_reactions(board) + for _ in range(9): + announce = await self.ctx.send(f"{self.current.user.mention}, your turn! React to emoji to mark field.") + timeout, pos = await self.current.get_move(self.board, board) + await announce.delete() + if timeout: + await self.ctx.send(f"{self.current.user.mention} ran out of time. Canceling game.") + self.over = True + return + self.board[pos] = self.current.symbol + await self.edit_board(board) + await board.clear_reaction(Emojis.number_emojis[pos]) + self.current, self.next = self.next, self.current + self.over = True + def is_channel_free() -> t.Callable: """Check is channel where command will be invoked free.""" @@ -175,6 +201,7 @@ class TicTacToe(Cog): if msg: await ctx.send(msg) return + await game.play() def setup(bot: SeasonalBot) -> None: -- cgit v1.2.3 From 94a39f3f7f1b19b678572d2d494f07535e52a32f Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Thu, 9 Apr 2020 19:05:33 +0300 Subject: (TicTacToe): Created helper function `Game.check_for_win`. --- bot/exts/evergreen/tic_tac_toe.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index b9e44220..970f359d 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -134,6 +134,24 @@ class Game: c = 0 await message.edit(content=msg) + async def check_for_win(self) -> bool: + """Check from board, is any player won game.""" + if ( + # Horizontal + self.board[1] == self.board[2] == self.board[3] + or self.board[4] == self.board[5] == self.board[6] + or self.board[7] == self.board[8] == self.board[9] + # Vertical + or self.board[1] == self.board[4] == self.board[7] + or self.board[2] == self.board[5] == self.board[8] + or self.board[3] == self.board[6] == self.board[9] + # Diagonal + or self.board[1] == self.board[5] == self.board[9] + or self.board[3] == self.board[5] == self.board[7] + ): + return True + return False + async def play(self) -> None: """Start and handle game.""" await self.ctx.send("It's time for game! Let's begin.") -- cgit v1.2.3 From 310ac58be883f07a9a410ce19c6b0dd8ffcf09bd Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Thu, 9 Apr 2020 19:10:24 +0300 Subject: (TicTacToe): Added winner check to `Game.play`. --- bot/exts/evergreen/tic_tac_toe.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index 970f359d..ed612182 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -169,7 +169,12 @@ class Game: self.board[pos] = self.current.symbol await self.edit_board(board) await board.clear_reaction(Emojis.number_emojis[pos]) + if await self.check_for_win(): + await self.ctx.send(f":tada: {self.current.user.mention} is won this game! :tada:") + await board.clear_reactions() + break self.current, self.next = self.next, self.current + self.over = True -- cgit v1.2.3 From 235e8d9b9b3360e9ebc2a49c2ba0c4006fe5ae9f Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Thu, 9 Apr 2020 19:11:24 +0300 Subject: (TicTacToe): Removed unnecessary variable `channel` from `Game`. --- bot/exts/evergreen/tic_tac_toe.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index ed612182..e8aafa07 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -46,8 +46,7 @@ class Player: class Game: """Class that contains information and functions about Tic Tac Toe game.""" - def __init__(self, channel: discord.TextChannel, players: t.List[Player], ctx: Context): - self.channel = channel + def __init__(self, players: t.List[Player], ctx: Context): self.players = players self.ctx = ctx self.board = { @@ -213,7 +212,6 @@ class TicTacToe(Cog): await ctx.send("Opponent is already in game.") return game = Game( - ctx.channel, [Player(ctx.author, ctx, Emojis.x), Player(opponent, ctx, Emojis.o)], ctx ) -- cgit v1.2.3 From b15c637568f33b2600e822a5aff54a90ea02f91f Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Thu, 9 Apr 2020 19:14:25 +0300 Subject: (TicTacToe): Added check that don't allow you to play against yourself to `tictactoe` command. --- bot/exts/evergreen/tic_tac_toe.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index e8aafa07..f1e0834b 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -206,6 +206,9 @@ class TicTacToe(Cog): @command(name="tictactoe", aliases=("ttt",)) async def tic_tac_toe(self, ctx: Context, opponent: discord.User) -> None: """Tic Tac Toe game. Play agains friends. Use reactions to add your mark to field.""" + if opponent == ctx.author: + await ctx.send("You can't play against yourself.") + return if not all( opponent not in (player.user for player in g.players) for g in ctx.cog.games if not g.over ): -- cgit v1.2.3 From a2963c4b2cf3f81e845b5e223a1b4de6feac0fda Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Thu, 9 Apr 2020 19:15:55 +0300 Subject: (TicTacToe): Added loser and winner attaching to `Game.play` winning handling. --- bot/exts/evergreen/tic_tac_toe.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index f1e0834b..27bdbda1 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -169,6 +169,8 @@ class Game: await self.edit_board(board) await board.clear_reaction(Emojis.number_emojis[pos]) if await self.check_for_win(): + self.winner = self.current + self.loser = self.next await self.ctx.send(f":tada: {self.current.user.mention} is won this game! :tada:") await board.clear_reactions() break -- cgit v1.2.3 From b362d24b225e5d1d101e784d84227d563b226c64 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Thu, 9 Apr 2020 19:27:37 +0300 Subject: (TicTacToe): Added new variable to `Game` class: `canceled`, applied it's changes and created new `tictactoe history` command. --- bot/exts/evergreen/tic_tac_toe.py | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index 27bdbda1..c1f780cf 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -2,10 +2,11 @@ import asyncio import typing as t import discord -from discord.ext.commands import Cog, Context, check, command, guild_only +from discord.ext.commands import Cog, Context, check, group, guild_only from bot.bot import SeasonalBot from bot.constants import Emojis +from bot.utils.pagination import LinePaginator CONFIRMATION_MESSAGE = ( "{opponent}, {requester} want to play Tic-Tac-Toe against you. React to this message with " @@ -67,6 +68,7 @@ class Game: self.winner: t.Optional[Player] = None self.loser: t.Optional[Player] = None self.over = False + self.canceled = False async def get_confirmation(self) -> t.Tuple[bool, t.Optional[str]]: """Ask does user want to play TicTacToe against requester. First player is always requester.""" @@ -94,6 +96,7 @@ class Game: ) except asyncio.TimeoutError: self.over = True + self.canceled = True await confirm_message.delete() return False, "Running out of time... Cancelled game." @@ -102,6 +105,7 @@ class Game: return True, None else: self.over = True + self.canceled = True return False, "User declined" async def add_reactions(self, msg: discord.Message) -> None: @@ -164,6 +168,7 @@ class Game: if timeout: await self.ctx.send(f"{self.current.user.mention} ran out of time. Canceling game.") self.over = True + self.canceled = True return self.board[pos] = self.current.symbol await self.edit_board(board) @@ -205,7 +210,7 @@ class TicTacToe(Cog): @guild_only() @is_channel_free() @is_requester_free() - @command(name="tictactoe", aliases=("ttt",)) + @group(name="tictactoe", aliases=("ttt",), invoke_without_command=True) async def tic_tac_toe(self, ctx: Context, opponent: discord.User) -> None: """Tic Tac Toe game. Play agains friends. Use reactions to add your mark to field.""" if opponent == ctx.author: @@ -229,6 +234,23 @@ class TicTacToe(Cog): return await game.play() + @tic_tac_toe.group(name="history", aliases=("log",), invoke_without_command=True) + async def tic_tac_toe_logs(self, ctx: Context) -> None: + """Show most recent tic-tac-toe games.""" + if len(self.games) < 1: + await ctx.send("No recent games.") + return + await LinePaginator.paginate( + ( + f"**#{i+1}**: {game.winner.user.mention} :trophy: vs {game.loser.user.mention}" + for i, game in enumerate(self.games) + if game.over + and not game.canceled + ), + ctx, + discord.Embed(title="Most recent Tic Tac Toe games") + ) + def setup(bot: SeasonalBot) -> None: """Load TicTacToe Cog.""" -- cgit v1.2.3 From 2d22d7b791416adea1052175da386a196d19d1a8 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Thu, 9 Apr 2020 19:28:44 +0300 Subject: (TicTacToe): Added way to send board to custom channel in `Game.send_board`. --- bot/exts/evergreen/tic_tac_toe.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index c1f780cf..87a845f1 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -113,7 +113,7 @@ class Game: for nr in Emojis.number_emojis.values(): await msg.add_reaction(nr) - async def send_board(self) -> discord.Message: + async def send_board(self, channel: t.Optional[discord.TextChannel] = None) -> discord.Message: """Send board and return it's message.""" msg = "" c = 0 @@ -123,6 +123,8 @@ class Game: if c == 3: msg += "\n" c = 0 + if channel: + return await channel.send(msg) return await self.ctx.send(msg) async def edit_board(self, message: discord.Message) -> None: -- cgit v1.2.3 From 14e5cadcbd8344cdba0b410567525f7518ac0a7a Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Thu, 9 Apr 2020 19:39:07 +0300 Subject: (TicTacToe): Created command to show game information `tictactoe history show `. --- bot/exts/evergreen/tic_tac_toe.py | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index 87a845f1..a9971ad2 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -253,6 +253,16 @@ class TicTacToe(Cog): discord.Embed(title="Most recent Tic Tac Toe games") ) + @tic_tac_toe_logs.command(name="show", aliases=("s",)) + async def show_tic_tac_toe_board(self, ctx: Context, game_id: int) -> None: + """View game board by ID (ID is possible to get by `.tictactoe history`).""" + if len(self.games) < game_id: + await ctx.send("Game don't exist.") + return + game = self.games[game_id - 1] + await ctx.send(f"{game.winner.user} :trophy: vs {game.loser.user}") + await game.send_board(ctx.channel) + def setup(bot: SeasonalBot) -> None: """Load TicTacToe Cog.""" -- cgit v1.2.3 From 5e13a3e2a7b6ed4b93e306784fae8443bf2cab33 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Sun, 12 Apr 2020 18:41:37 +0300 Subject: (TicTacToe): Created `AI` class for Tic Tac Toe against computer playing. --- bot/exts/evergreen/tic_tac_toe.py | 47 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index a9971ad2..b306e803 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -1,4 +1,5 @@ import asyncio +import random import typing as t import discord @@ -44,6 +45,52 @@ class Player: return False, list(Emojis.number_emojis.keys())[list(Emojis.number_emojis.values()).index(react.emoji)] +class AI: + """Tic Tac Toe AI class for against computer gaming.""" + + def __init__(self, symbol: str): + self.symbol = symbol + + async def check_win(self, board: t.Dict[int, str]) -> bool: + """Check does this move will result game end.""" + if ( + # Horizontal + board[1] == board[2] == board[3] + or board[4] == board[5] == board[6] + or board[7] == board[8] == board[9] + # Vertical + or board[1] == board[4] == board[7] + or board[2] == board[5] == board[8] + or board[3] == board[6] == board[9] + # Diagonal + or board[1] == board[5] == board[9] + or board[3] == board[5] == board[7] + ): + return True + return False + + async def get_move(self, board: t.Dict[int, str], _: discord.Message) -> t.Tuple[bool, int]: + """Get move from AI. AI use Minimax strategy.""" + possible_moves = [i for i, emoji in board.items() if emoji in Emojis.number_emojis] + + for symbol in (Emojis.x, Emojis.o): + for move in possible_moves: + board_copy = board.copy() + board_copy[move] = symbol + if self.check_win(board_copy): + return False, move + + open_corners = [i for i in possible_moves if i in (1, 3, 7, 9)] + if len(open_corners) > 0: + return False, random.choice(open_corners) + + if 5 in possible_moves: + return False, 5 + + open_edges = [i for i in possible_moves if i in (2, 4, 6, 8)] + return False, random.choice(open_edges) + + class Game: """Class that contains information and functions about Tic Tac Toe game.""" -- cgit v1.2.3 From 85ed1469cefd408233fcdb84643089b4b6a36d88 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Sun, 12 Apr 2020 19:14:18 +0300 Subject: (TicTacToe): Implemented AI to game and cog. --- bot/exts/evergreen/tic_tac_toe.py | 82 ++++++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 28 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index b306e803..fc8edd70 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -71,13 +71,13 @@ class AI: async def get_move(self, board: t.Dict[int, str], _: discord.Message) -> t.Tuple[bool, int]: """Get move from AI. AI use Minimax strategy.""" - possible_moves = [i for i, emoji in board.items() if emoji in Emojis.number_emojis] + possible_moves = [i for i, emoji in board.items() if emoji in list(Emojis.number_emojis.values())] for symbol in (Emojis.x, Emojis.o): for move in possible_moves: board_copy = board.copy() board_copy[move] = symbol - if self.check_win(board_copy): + if await self.check_win(board_copy): return False, move open_corners = [i for i in possible_moves if i in (1, 3, 7, 9)] @@ -94,7 +94,7 @@ class AI: class Game: """Class that contains information and functions about Tic Tac Toe game.""" - def __init__(self, players: t.List[Player], ctx: Context): + def __init__(self, players: t.List[t.Union[Player, AI]], ctx: Context): self.players = players self.ctx = ctx self.board = { @@ -112,10 +112,11 @@ class Game: self.current = self.players[0] self.next = self.players[1] - self.winner: t.Optional[Player] = None - self.loser: t.Optional[Player] = None + self.winner: t.Optional[t.Union[Player, AI]] = None + self.loser: t.Optional[t.Union[Player, AI]] = None self.over = False self.canceled = False + self.draw = False async def get_confirmation(self) -> t.Tuple[bool, t.Optional[str]]: """Ask does user want to play TicTacToe against requester. First player is always requester.""" @@ -211,9 +212,11 @@ class Game: await self.add_reactions(board) for _ in range(9): - announce = await self.ctx.send(f"{self.current.user.mention}, your turn! React to emoji to mark field.") + if isinstance(self.current, Player): + announce = await self.ctx.send(f"{self.current.user.mention}, your turn! React to emoji to mark field.") timeout, pos = await self.current.get_move(self.board, board) - await announce.delete() + if isinstance(self.current, Player): + await announce.delete() if timeout: await self.ctx.send(f"{self.current.user.mention} ran out of time. Canceling game.") self.over = True @@ -225,11 +228,16 @@ class Game: if await self.check_for_win(): self.winner = self.current self.loser = self.next - await self.ctx.send(f":tada: {self.current.user.mention} is won this game! :tada:") + await self.ctx.send( + f":tada: {self.current.user.mention if isinstance(self.current, Player) else 'AI'} " + f"is won this game! :tada:" + ) await board.clear_reactions() break self.current, self.next = self.next, self.current - + if not self.winner: + self.draw = True + await self.ctx.send("It's DRAW!") self.over = True @@ -260,27 +268,34 @@ class TicTacToe(Cog): @is_channel_free() @is_requester_free() @group(name="tictactoe", aliases=("ttt",), invoke_without_command=True) - async def tic_tac_toe(self, ctx: Context, opponent: discord.User) -> None: - """Tic Tac Toe game. Play agains friends. Use reactions to add your mark to field.""" + async def tic_tac_toe(self, ctx: Context, opponent: t.Optional[discord.User]) -> None: + """Tic Tac Toe game. Play agains friends or AI. Use reactions to add your mark to field.""" if opponent == ctx.author: await ctx.send("You can't play against yourself.") return - if not all( + if opponent is not None and not all( opponent not in (player.user for player in g.players) for g in ctx.cog.games if not g.over ): await ctx.send("Opponent is already in game.") return - game = Game( - [Player(ctx.author, ctx, Emojis.x), Player(opponent, ctx, Emojis.o)], - ctx - ) + if opponent is None: + game = Game( + [Player(ctx.author, ctx, Emojis.x), AI(Emojis.o)], + ctx + ) + else: + game = Game( + [Player(ctx.author, ctx, Emojis.x), Player(opponent, ctx, Emojis.o)], + ctx + ) self.games.append(game) - confirmed, msg = await game.get_confirmation() + if opponent is not None: + confirmed, msg = await game.get_confirmation() - if not confirmed: - if msg: - await ctx.send(msg) - return + if not confirmed: + if msg: + await ctx.send(msg) + return await game.play() @tic_tac_toe.group(name="history", aliases=("log",), invoke_without_command=True) @@ -289,13 +304,21 @@ class TicTacToe(Cog): if len(self.games) < 1: await ctx.send("No recent games.") return + log_games = [] + for i, game in enumerate(self.games): + if game.over and not game.canceled: + if game.draw: + log_games.append( + f"**#{i+1}**: {game.players[0].user.mention} vs " + f"{game.players[1].user.mention if isinstance(game.players[1], Player) else 'AI'} (draw)" + ) + else: + log_games.append( + f"**#{i+1}**: {game.winner.user.mention if isinstance(game.winner, Player) else 'AI'} :trophy: " + f"vs {game.loser.user.mention if isinstance(game.loser, Player) else 'AI'}" + ) await LinePaginator.paginate( - ( - f"**#{i+1}**: {game.winner.user.mention} :trophy: vs {game.loser.user.mention}" - for i, game in enumerate(self.games) - if game.over - and not game.canceled - ), + log_games, ctx, discord.Embed(title="Most recent Tic Tac Toe games") ) @@ -307,7 +330,10 @@ class TicTacToe(Cog): await ctx.send("Game don't exist.") return game = self.games[game_id - 1] - await ctx.send(f"{game.winner.user} :trophy: vs {game.loser.user}") + await ctx.send( + f"{game.winner.user if isinstance(game.winner, Player) else 'AI'} " + f":trophy: vs {game.loser.user if isinstance(game.winner, Player) else 'AI'}" + ) await game.send_board(ctx.channel) -- cgit v1.2.3 From af6357c444cd55fb203cf9696f9b568b27ccd666 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Sun, 12 Apr 2020 19:17:15 +0300 Subject: (TicTacToe): Setting winning as priority in AI instead blocking opponent. --- bot/exts/evergreen/tic_tac_toe.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index fc8edd70..72eb2090 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -73,7 +73,7 @@ class AI: """Get move from AI. AI use Minimax strategy.""" possible_moves = [i for i, emoji in board.items() if emoji in list(Emojis.number_emojis.values())] - for symbol in (Emojis.x, Emojis.o): + for symbol in (Emojis.o, Emojis.x): for move in possible_moves: board_copy = board.copy() board_copy[move] = symbol -- cgit v1.2.3 From ddec3a15ffa37b775bc483910baefb4e0aba2f88 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Mon, 13 Apr 2020 08:14:42 +0300 Subject: (TicTacToe): Created new helper functions `display` to `Player` and `AI` class to avoid `if` checks in strings. --- bot/exts/evergreen/tic_tac_toe.py | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index 72eb2090..8d0c384b 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -44,6 +44,10 @@ class Player: else: return False, list(Emojis.number_emojis.keys())[list(Emojis.number_emojis.values()).index(react.emoji)] + async def display(self) -> str: + """Return mention of user.""" + return self.user.mention + class AI: """Tic Tac Toe AI class for against computer gaming.""" @@ -90,6 +94,10 @@ class AI: open_edges = [i for i in possible_moves if i in (2, 4, 6, 8)] return False, random.choice(open_edges) + def display(self) -> str: + """Return `AI` as user name.""" + return "AI" + class Game: """Class that contains information and functions about Tic Tac Toe game.""" -- cgit v1.2.3 From 494cb28681f2de44ff4f95b1b9fe4b1662239cb6 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Mon, 13 Apr 2020 08:19:10 +0300 Subject: (TicTacToe): Applied `Player.display()` and `AI.display()` to cog and `Game` class. --- bot/exts/evergreen/tic_tac_toe.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index 8d0c384b..435c7af3 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -237,8 +237,7 @@ class Game: self.winner = self.current self.loser = self.next await self.ctx.send( - f":tada: {self.current.user.mention if isinstance(self.current, Player) else 'AI'} " - f"is won this game! :tada:" + f":tada: {self.current.display()} is won this game! :tada:" ) await board.clear_reactions() break @@ -317,13 +316,11 @@ class TicTacToe(Cog): if game.over and not game.canceled: if game.draw: log_games.append( - f"**#{i+1}**: {game.players[0].user.mention} vs " - f"{game.players[1].user.mention if isinstance(game.players[1], Player) else 'AI'} (draw)" + f"**#{i+1}**: {game.players[0].display()} vs {game.players[1].display()} (draw)" ) else: log_games.append( - f"**#{i+1}**: {game.winner.user.mention if isinstance(game.winner, Player) else 'AI'} :trophy: " - f"vs {game.loser.user.mention if isinstance(game.loser, Player) else 'AI'}" + f"**#{i+1}**: {game.winner.display()} :trophy: vs {game.loser.display()}" ) await LinePaginator.paginate( log_games, @@ -339,8 +336,7 @@ class TicTacToe(Cog): return game = self.games[game_id - 1] await ctx.send( - f"{game.winner.user if isinstance(game.winner, Player) else 'AI'} " - f":trophy: vs {game.loser.user if isinstance(game.winner, Player) else 'AI'}" + f"{game.winner.display()} :trophy: vs {game.loser.display()}" ) await game.send_board(ctx.channel) -- cgit v1.2.3 From d3690c4056826d963c4a25b8fc7f5704aa8e93e1 Mon Sep 17 00:00:00 2001 From: Hambira Date: Sat, 30 May 2020 22:36:45 +0530 Subject: "adding xkcd feature" --- bot/exts/evergreen/xkcd.py | 72 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 bot/exts/evergreen/xkcd.py (limited to 'bot') diff --git a/bot/exts/evergreen/xkcd.py b/bot/exts/evergreen/xkcd.py new file mode 100644 index 00000000..11477216 --- /dev/null +++ b/bot/exts/evergreen/xkcd.py @@ -0,0 +1,72 @@ +import logging +import random + +import discord +from discord.ext import commands + +log = logging.getLogger(__name__) + + +class XKCD(commands.Cog): + """A cog for posting the XKCD .""" + + def __init__(self, bot: commands.Bot): + self.bot = bot + + @commands.command(name="xkcd") + async def fetch_xkcd_comics(self, ctx: commands.Context, comic: str = "latest") -> None: + """Read your Fav XKCD comics.""" + if comic not in ["random", "latest"]: + url = f"https://xkcd.com/{comic}/info.0.json" + else: + url = "https://xkcd.com/info.0.json" + + # ---- random choice ----- + if comic == "random": + async with self.bot.http_session.get(url) as r: + json_data = await r.json() + random_pick = random.randint(1, int(json_data["num"])) + url = f"https://xkcd.com/{random_pick}/info.0.json" + + log.trace(f"Querying xkcd API: {url}") + async with self.bot.http_session.get(url) as r: + if r.status == "200": + json_data = await r.json() + else: + # ----- Exception handling | Guides to use ------ + log.warning(f"Received response {r.status} from: {url}") + # -- get the latest comic number --- + url = f"https://xkcd.com/info.0.json" + async with self.bot.http_session.get(url) as r: + latest_data = await r.json() + + # --- beautify response --- + latest_num = latest_data["num"] + resp = discord.Embed( + title="Guides | Usage", + description=f''' + .xkcd latest (Retrieves the latest comic) + .xkcd random (Retrieves random comic) + .xkcd number (Enter a comic number between 1 & {latest_num}) + ''' + ) + return await ctx.send(embed=resp) + + # --- response variables ---- + day, month, year = json_data["day"], json_data["month"], json_data["year"] + comic_number = json_data["num"] + + # ---- beautify response ---- + embed = discord.Embed( + title=json_data['title'], + description=json_data["alt"] + ) + embed.set_image(url=json_data['img']) + embed.set_footer(text=f"Post date : {day}-{month}-{year} | xkcd comics - {comic_number}") + + await ctx.send(embed=embed) + + +def setup(bot: commands.Bot) -> None: + """XKCD Cog load.""" + bot.add_cog(XKCD(bot)) -- cgit v1.2.3 From 8df212d6ca6bb44668da57fa99bae78871f2e864 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Thu, 24 Sep 2020 17:33:06 +0300 Subject: Tictactoe: Use __str__ instead custom display method for user/AI name display --- bot/exts/evergreen/tic_tac_toe.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index 435c7af3..74b04db8 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -44,7 +44,7 @@ class Player: else: return False, list(Emojis.number_emojis.keys())[list(Emojis.number_emojis.values()).index(react.emoji)] - async def display(self) -> str: + def __str__(self) -> str: """Return mention of user.""" return self.user.mention @@ -94,7 +94,7 @@ class AI: open_edges = [i for i in possible_moves if i in (2, 4, 6, 8)] return False, random.choice(open_edges) - def display(self) -> str: + def __str__(self) -> str: """Return `AI` as user name.""" return "AI" @@ -237,7 +237,7 @@ class Game: self.winner = self.current self.loser = self.next await self.ctx.send( - f":tada: {self.current.display()} is won this game! :tada:" + f":tada: {self.current} is won this game! :tada:" ) await board.clear_reactions() break @@ -316,11 +316,11 @@ class TicTacToe(Cog): if game.over and not game.canceled: if game.draw: log_games.append( - f"**#{i+1}**: {game.players[0].display()} vs {game.players[1].display()} (draw)" + f"**#{i+1}**: {game.players[0]} vs {game.players[1]} (draw)" ) else: log_games.append( - f"**#{i+1}**: {game.winner.display()} :trophy: vs {game.loser.display()}" + f"**#{i+1}**: {game.winner} :trophy: vs {game.loser}" ) await LinePaginator.paginate( log_games, @@ -336,7 +336,7 @@ class TicTacToe(Cog): return game = self.games[game_id - 1] await ctx.send( - f"{game.winner.display()} :trophy: vs {game.loser.display()}" + f"{game.winner} :trophy: vs {game.loser}" ) await game.send_board(ctx.channel) -- cgit v1.2.3 From 0a275c90bfd824b320dd36c9b8c5fd73a143ad72 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Thu, 24 Sep 2020 20:00:44 +0300 Subject: Tictactoe: Refactor board message content generation --- bot/exts/evergreen/tic_tac_toe.py | 37 +++++++++---------------------------- 1 file changed, 9 insertions(+), 28 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index 74b04db8..16871070 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -169,31 +169,12 @@ class Game: for nr in Emojis.number_emojis.values(): await msg.add_reaction(nr) - async def send_board(self, channel: t.Optional[discord.TextChannel] = None) -> discord.Message: - """Send board and return it's message.""" - msg = "" - c = 0 - for line in self.board.values(): - msg += f"{line} " - c += 1 - if c == 3: - msg += "\n" - c = 0 - if channel: - return await channel.send(msg) - return await self.ctx.send(msg) - - async def edit_board(self, message: discord.Message) -> None: - """Edit Tic Tac Toe game board in message.""" - msg = "" - c = 0 - for line in self.board.values(): - msg += f"{line} " - c += 1 - if c == 3: - msg += "\n" - c = 0 - await message.edit(content=msg) + def format_board(self) -> str: + """Get formatted tic-tac-toe board for message.""" + board = list(self.board.values()) + return "\n".join( + (f"{board[line]} {board[line + 1]} {board[line + 2]}" for line in range(0, len(board), 3)) + ) async def check_for_win(self) -> bool: """Check from board, is any player won game.""" @@ -216,7 +197,7 @@ class Game: async def play(self) -> None: """Start and handle game.""" await self.ctx.send("It's time for game! Let's begin.") - board = await self.send_board() + board = await self.ctx.send(self.format_board()) await self.add_reactions(board) for _ in range(9): @@ -231,7 +212,7 @@ class Game: self.canceled = True return self.board[pos] = self.current.symbol - await self.edit_board(board) + await board.edit(content=self.format_board()) await board.clear_reaction(Emojis.number_emojis[pos]) if await self.check_for_win(): self.winner = self.current @@ -338,7 +319,7 @@ class TicTacToe(Cog): await ctx.send( f"{game.winner} :trophy: vs {game.loser}" ) - await game.send_board(ctx.channel) + await ctx.send(game.format_board()) def setup(bot: SeasonalBot) -> None: -- cgit v1.2.3 From e6ca49b4745a3c568da6adf3e8c670661b15443d Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Thu, 24 Sep 2020 20:04:30 +0300 Subject: Tictactoe: Document `get_confirmation` return value --- bot/exts/evergreen/tic_tac_toe.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index 16871070..0c13964a 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -127,7 +127,13 @@ class Game: self.draw = False async def get_confirmation(self) -> t.Tuple[bool, t.Optional[str]]: - """Ask does user want to play TicTacToe against requester. First player is always requester.""" + """ + Ask does user want to play TicTacToe against requester. First player is always requester. + + This return tuple that have: + - first element boolean (is game accepted?) + - (optional, only when first element is False, otherwise None) reason for declining. + """ confirm_message = await self.ctx.send( CONFIRMATION_MESSAGE.format( opponent=self.players[1].user.mention, -- cgit v1.2.3 From fdc4cbd258a66f37371e427c57271b8abf8378e5 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Thu, 24 Sep 2020 20:11:25 +0300 Subject: Tictactoe: Remove duplicate functions --- bot/exts/evergreen/tic_tac_toe.py | 62 +++++++++++++++------------------------ 1 file changed, 24 insertions(+), 38 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index 0c13964a..26df4e10 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -15,6 +15,25 @@ CONFIRMATION_MESSAGE = ( ) +def check_win(board: t.Dict[int, str]) -> bool: + """Check from board, is any player won game.""" + if ( + # Horizontal + board[1] == board[2] == board[3] + or board[4] == board[5] == board[6] + or board[7] == board[8] == board[9] + # Vertical + or board[1] == board[4] == board[7] + or board[2] == board[5] == board[8] + or board[3] == board[6] == board[9] + # Diagonal + or board[1] == board[5] == board[9] + or board[3] == board[5] == board[7] + ): + return True + return False + + class Player: """Class that contains information about player and functions that interact with player.""" @@ -55,24 +74,6 @@ class AI: def __init__(self, symbol: str): self.symbol = symbol - async def check_win(self, board: t.Dict[int, str]) -> bool: - """Check does this move will result game end.""" - if ( - # Horizontal - board[1] == board[2] == board[3] - or board[4] == board[5] == board[6] - or board[7] == board[8] == board[9] - # Vertical - or board[1] == board[4] == board[7] - or board[2] == board[5] == board[8] - or board[3] == board[6] == board[9] - # Diagonal - or board[1] == board[5] == board[9] - or board[3] == board[5] == board[7] - ): - return True - return False - async def get_move(self, board: t.Dict[int, str], _: discord.Message) -> t.Tuple[bool, int]: """Get move from AI. AI use Minimax strategy.""" possible_moves = [i for i, emoji in board.items() if emoji in list(Emojis.number_emojis.values())] @@ -81,7 +82,7 @@ class AI: for move in possible_moves: board_copy = board.copy() board_copy[move] = symbol - if await self.check_win(board_copy): + if check_win(board_copy): return False, move open_corners = [i for i in possible_moves if i in (1, 3, 7, 9)] @@ -144,6 +145,9 @@ class Game: await confirm_message.add_reaction(Emojis.decline) def confirm_check(reaction: discord.Reaction, user: discord.User) -> bool: + """ + Check is user who reacted user from who this was requested, message is confirm message and emoji is valid. + """ return ( reaction.emoji in (Emojis.confirmation, Emojis.decline) and reaction.message.id == confirm_message.id @@ -182,24 +186,6 @@ class Game: (f"{board[line]} {board[line + 1]} {board[line + 2]}" for line in range(0, len(board), 3)) ) - async def check_for_win(self) -> bool: - """Check from board, is any player won game.""" - if ( - # Horizontal - self.board[1] == self.board[2] == self.board[3] - or self.board[4] == self.board[5] == self.board[6] - or self.board[7] == self.board[8] == self.board[9] - # Vertical - or self.board[1] == self.board[4] == self.board[7] - or self.board[2] == self.board[5] == self.board[8] - or self.board[3] == self.board[6] == self.board[9] - # Diagonal - or self.board[1] == self.board[5] == self.board[9] - or self.board[3] == self.board[5] == self.board[7] - ): - return True - return False - async def play(self) -> None: """Start and handle game.""" await self.ctx.send("It's time for game! Let's begin.") @@ -220,7 +206,7 @@ class Game: self.board[pos] = self.current.symbol await board.edit(content=self.format_board()) await board.clear_reaction(Emojis.number_emojis[pos]) - if await self.check_for_win(): + if check_win(self.board): self.winner = self.current self.loser = self.next await self.ctx.send( -- cgit v1.2.3 From 88c5270cebb56c1cf84ea0a2bfb78cca6bf2252a Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Thu, 24 Sep 2020 20:14:09 +0300 Subject: Tictactoe: Document another check --- bot/exts/evergreen/tic_tac_toe.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index 26df4e10..1bd20b70 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -49,6 +49,9 @@ class Player: Return is timeout reached and position of field what user will fill when timeout don't reach. """ def check_for_move(r: discord.Reaction, u: discord.User) -> bool: + """ + Check does user who reacted is user who we want, message is board message and emoji is in board values. + """ return ( u.id == self.user.id and msg.id == r.message.id -- cgit v1.2.3 From d7c215e723da334f3ef3927c173680307d7764ba Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Thu, 24 Sep 2020 20:17:47 +0300 Subject: Tictactoe: Fix docstrings formatting --- bot/exts/evergreen/tic_tac_toe.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index 1bd20b70..20fbb9be 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -49,9 +49,7 @@ class Player: Return is timeout reached and position of field what user will fill when timeout don't reach. """ def check_for_move(r: discord.Reaction, u: discord.User) -> bool: - """ - Check does user who reacted is user who we want, message is board message and emoji is in board values. - """ + """Check does user who reacted is user who we want, message is board and emoji is in board values.""" return ( u.id == self.user.id and msg.id == r.message.id @@ -148,9 +146,7 @@ class Game: await confirm_message.add_reaction(Emojis.decline) def confirm_check(reaction: discord.Reaction, user: discord.User) -> bool: - """ - Check is user who reacted user from who this was requested, message is confirm message and emoji is valid. - """ + """Check is user who reacted from who this was requested, message is confirmation and emoji is valid.""" return ( reaction.emoji in (Emojis.confirmation, Emojis.decline) and reaction.message.id == confirm_message.id -- cgit v1.2.3 From 931fb3ea4a6eb767864b33df5bd17cfb48e1b919 Mon Sep 17 00:00:00 2001 From: Will Da Silva Date: Sun, 4 Oct 2020 22:44:49 -0400 Subject: Verify channel constants on startup Closes #393 --- bot/bot.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/bot.py b/bot/bot.py index ffaf4284..92873ba4 100644 --- a/bot/bot.py +++ b/bot/bot.py @@ -45,7 +45,7 @@ class SeasonalBot(commands.Bot): connector=TCPConnector(resolver=AsyncResolver(), family=socket.AF_INET) ) self._guild_available = asyncio.Event() - + self.loop.create_task(self.check_channels()) self.loop.create_task(self.send_log("SeasonalBot", "Connected!")) @property @@ -149,6 +149,15 @@ class SeasonalBot(commands.Bot): log.info("Nickname set successfully") return True + async def check_channels(self) -> None: + await self.wait_until_guild_available() + all_channels = set(self.get_all_channels()) + for name, channel_id in vars(Channels).items(): + if name.startswith('_'): + continue + if channel_id not in all_channels: + log.error(f'Channel "{name}" with id {channel_id} missing') + async def send_log(self, title: str, details: str = None, *, icon: str = None) -> None: """Send an embed message to the devlog channel.""" await self.wait_until_guild_available() -- cgit v1.2.3 From b907c4cc6e943904e506ec49d3a28d98e9073625 Mon Sep 17 00:00:00 2001 From: Will Da Silva Date: Sun, 4 Oct 2020 22:47:16 -0400 Subject: Add docstring to check_channels --- bot/bot.py | 1 + 1 file changed, 1 insertion(+) (limited to 'bot') diff --git a/bot/bot.py b/bot/bot.py index 92873ba4..c004414e 100644 --- a/bot/bot.py +++ b/bot/bot.py @@ -150,6 +150,7 @@ class SeasonalBot(commands.Bot): return True async def check_channels(self) -> None: + """Verifies that all channel constants refer to channels which exist.""" await self.wait_until_guild_available() all_channels = set(self.get_all_channels()) for name, channel_id in vars(Channels).items(): -- cgit v1.2.3 From 7bec6f4e9423d8e5a797a2a6e73cd235e0a5f0cf Mon Sep 17 00:00:00 2001 From: Will Da Silva Date: Sun, 4 Oct 2020 22:53:04 -0400 Subject: Capitalize "ID" in error message --- bot/bot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/bot.py b/bot/bot.py index c004414e..b486201e 100644 --- a/bot/bot.py +++ b/bot/bot.py @@ -157,7 +157,7 @@ class SeasonalBot(commands.Bot): if name.startswith('_'): continue if channel_id not in all_channels: - log.error(f'Channel "{name}" with id {channel_id} missing') + log.error(f'Channel "{name}" with ID {channel_id} missing') async def send_log(self, title: str, details: str = None, *, icon: str = None) -> None: """Send an embed message to the devlog channel.""" -- cgit v1.2.3 From fa7c5c68959b664c0b4d5d983cfaafc84d2759da Mon Sep 17 00:00:00 2001 From: xithrius Date: Fri, 8 Jan 2021 17:06:23 -0800 Subject: Corrected small spelling mistake. --- bot/exts/evergreen/tic_tac_toe.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index 20fbb9be..b27f1942 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -5,7 +5,7 @@ import typing as t import discord from discord.ext.commands import Cog, Context, check, group, guild_only -from bot.bot import SeasonalBot +from bot.bot import Bot from bot.constants import Emojis from bot.utils.pagination import LinePaginator @@ -239,7 +239,7 @@ def is_requester_free() -> t.Callable: class TicTacToe(Cog): """TicTacToe cog contains tic-tac-toe game commands.""" - def __init__(self, bot: SeasonalBot): + def __init__(self, bot: Bot): self.bot = bot self.games: t.List[Game] = [] @@ -248,7 +248,7 @@ class TicTacToe(Cog): @is_requester_free() @group(name="tictactoe", aliases=("ttt",), invoke_without_command=True) async def tic_tac_toe(self, ctx: Context, opponent: t.Optional[discord.User]) -> None: - """Tic Tac Toe game. Play agains friends or AI. Use reactions to add your mark to field.""" + """Tic Tac Toe game. Play against friends or AI. Use reactions to add your mark to field.""" if opponent == ctx.author: await ctx.send("You can't play against yourself.") return @@ -313,6 +313,6 @@ class TicTacToe(Cog): await ctx.send(game.format_board()) -def setup(bot: SeasonalBot) -> None: +def setup(bot: Bot) -> None: """Load TicTacToe Cog.""" bot.add_cog(TicTacToe(bot)) -- cgit v1.2.3 From 48103a601f48ac620adf8f97de7ab9f7ab942998 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Sat, 9 Jan 2021 08:21:44 +0200 Subject: Simplify check_win function returning --- bot/exts/evergreen/tic_tac_toe.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index b27f1942..d5c2a558 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -17,21 +17,21 @@ CONFIRMATION_MESSAGE = ( def check_win(board: t.Dict[int, str]) -> bool: """Check from board, is any player won game.""" - if ( + return any( + ( # Horizontal - board[1] == board[2] == board[3] - or board[4] == board[5] == board[6] - or board[7] == board[8] == board[9] + board[1] == board[2] == board[3], + board[4] == board[5] == board[6], + board[7] == board[8] == board[9], # Vertical - or board[1] == board[4] == board[7] - or board[2] == board[5] == board[8] - or board[3] == board[6] == board[9] + board[1] == board[4] == board[7], + board[2] == board[5] == board[8], + board[3] == board[6] == board[9], # Diagonal - or board[1] == board[5] == board[9] - or board[3] == board[5] == board[7] - ): - return True - return False + board[1] == board[5] == board[9], + board[3] == board[5] == board[7], + ) + ) class Player: -- cgit v1.2.3 From 97ef76a6206a69d4ab58ca9de9c980afa4ca20c6 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Sat, 16 Jan 2021 20:12:51 +0200 Subject: Move Tic Tac Toe board to embed description --- bot/exts/evergreen/tic_tac_toe.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index d5c2a558..a206aee7 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -188,7 +188,9 @@ class Game: async def play(self) -> None: """Start and handle game.""" await self.ctx.send("It's time for game! Let's begin.") - board = await self.ctx.send(self.format_board()) + board = await self.ctx.send( + embed=discord.Embed(description=self.format_board()) + ) await self.add_reactions(board) for _ in range(9): @@ -203,7 +205,9 @@ class Game: self.canceled = True return self.board[pos] = self.current.symbol - await board.edit(content=self.format_board()) + await board.edit( + embed=discord.Embed(description=self.format_board()) + ) await board.clear_reaction(Emojis.number_emojis[pos]) if check_win(self.board): self.winner = self.current -- cgit v1.2.3 From 3fcddb2e7d4e855eef815df9e3552fce929ce00f Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Sat, 16 Jan 2021 20:27:58 +0200 Subject: Fix grammar Co-authored-by: ChrisJL --- bot/exts/evergreen/tic_tac_toe.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index a206aee7..db84427c 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -10,7 +10,7 @@ from bot.constants import Emojis from bot.utils.pagination import LinePaginator CONFIRMATION_MESSAGE = ( - "{opponent}, {requester} want to play Tic-Tac-Toe against you. React to this message with " + "{opponent}, {requester} wants to play Tic-Tac-Toe against you. React to this message with " f"{Emojis.confirmation} to accept or with {Emojis.decline} to decline." ) -- cgit v1.2.3 From fb09472ddc9a52b4bcc78ce2f67f2ac768c8a8ec Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Sat, 16 Jan 2021 20:33:47 +0200 Subject: Add missing a article Co-authored-by: ChrisJL --- bot/exts/evergreen/tic_tac_toe.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index db84427c..4b76f94d 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -220,7 +220,7 @@ class Game: self.current, self.next = self.next, self.current if not self.winner: self.draw = True - await self.ctx.send("It's DRAW!") + await self.ctx.send("It's a DRAW!") self.over = True -- cgit v1.2.3 From 6a3366a03de682f6d00aef9bfe33d7c8a10e6ba7 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Sat, 16 Jan 2021 20:35:28 +0200 Subject: Improve "your turn" message --- bot/exts/evergreen/tic_tac_toe.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index 4b76f94d..49571a34 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -195,7 +195,7 @@ class Game: for _ in range(9): if isinstance(self.current, Player): - announce = await self.ctx.send(f"{self.current.user.mention}, your turn! React to emoji to mark field.") + announce = await self.ctx.send(f"{self.current.user.mention}, it's your turn! React with an emoji to take your go.") timeout, pos = await self.current.get_move(self.board, board) if isinstance(self.current, Player): await announce.delete() -- cgit v1.2.3 From e2878ab625b7add00fe6aea3175107c9bd9e1cdb Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Sat, 16 Jan 2021 20:37:11 +0200 Subject: More grammar fixes --- bot/exts/evergreen/tic_tac_toe.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index 49571a34..ed4a6d52 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -187,7 +187,7 @@ class Game: async def play(self) -> None: """Start and handle game.""" - await self.ctx.send("It's time for game! Let's begin.") + await self.ctx.send("It's time for the game! Let's begin.") board = await self.ctx.send( embed=discord.Embed(description=self.format_board()) ) @@ -213,7 +213,7 @@ class Game: self.winner = self.current self.loser = self.next await self.ctx.send( - f":tada: {self.current} is won this game! :tada:" + f":tada: {self.current} won this game! :tada:" ) await board.clear_reactions() break -- cgit v1.2.3 From b5490070a481d09a82e682be0b822baab4fc373e Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Sat, 16 Jan 2021 20:48:27 +0200 Subject: Fix too long line --- bot/exts/evergreen/tic_tac_toe.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index ed4a6d52..bcc4c97e 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -195,7 +195,10 @@ class Game: for _ in range(9): if isinstance(self.current, Player): - announce = await self.ctx.send(f"{self.current.user.mention}, it's your turn! React with an emoji to take your go.") + announce = await self.ctx.send( + f"{self.current.user.mention}, it's your turn! " + "React with an emoji to take your go." + ) timeout, pos = await self.current.get_move(self.board, board) if isinstance(self.current, Player): await announce.delete() -- cgit v1.2.3 From 674147c2858dfb6e10470d7b4c044f46615950e3 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Sun, 17 Jan 2021 08:32:00 +0200 Subject: Remove unnecessary line split Co-authored-by: Xithrius <15021300+Xithrius@users.noreply.github.com> --- bot/exts/evergreen/tic_tac_toe.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index bcc4c97e..daa646a8 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -314,9 +314,7 @@ class TicTacToe(Cog): await ctx.send("Game don't exist.") return game = self.games[game_id - 1] - await ctx.send( - f"{game.winner} :trophy: vs {game.loser}" - ) + await ctx.send(f"{game.winner} :trophy: vs {game.loser}") await ctx.send(game.format_board()) -- cgit v1.2.3 From 1d6912caf4bf3cb0604933ec66fa13294fa5d68a Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Sun, 17 Jan 2021 08:38:20 +0200 Subject: Fix indention --- bot/exts/evergreen/tic_tac_toe.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index daa646a8..22fff102 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -314,7 +314,7 @@ class TicTacToe(Cog): await ctx.send("Game don't exist.") return game = self.games[game_id - 1] - await ctx.send(f"{game.winner} :trophy: vs {game.loser}") + await ctx.send(f"{game.winner} :trophy: vs {game.loser}") await ctx.send(game.format_board()) -- cgit v1.2.3 From 3616302122f72c19b6ab4877fdb6a5236967110d Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Tue, 19 Jan 2021 06:37:09 +0530 Subject: Add connect four cog supporting player vs player and player vs ai --- bot/exts/evergreen/connect_four.py | 377 +++++++++++++++++++++++++++++++++++++ 1 file changed, 377 insertions(+) create mode 100644 bot/exts/evergreen/connect_four.py (limited to 'bot') diff --git a/bot/exts/evergreen/connect_four.py b/bot/exts/evergreen/connect_four.py new file mode 100644 index 00000000..9519f124 --- /dev/null +++ b/bot/exts/evergreen/connect_four.py @@ -0,0 +1,377 @@ +import asyncio +import random +import typing +from functools import partial + +import discord +from discord.ext import commands + +EMOJIS = [":white_circle:", ":blue_circle:", ":red_circle:"] +NUMBERS = [ + ":one:", + ":two:", + ":three:", + ":four:", + ":five:", + ":six:", + ":seven:", + ":eight:", + ":nine:" +] +UNICODE_NUMBERS = [ + "\u0031\u20e3", + "\u0032\u20e3", + "\u0033\u20e3", + "\u0034\u20e3", + "\u0035\u20e3", + "\u0036\u20e3", + "\u0037\u20e3", + "\u0038\u20e3", + "\u0039\u20e3", +] +CROSS_EMOJI = "\u274e" +HAND_RAISED_EMOJI = "\U0001f64b" +Coordinate = typing.Optional[typing.Tuple[int, int]] + + +class Game: + """A Connect 4 Game.""" + + def __init__( + self, + bot: commands.Bot, + channel: discord.TextChannel, + player1: discord.Member, + player2: discord.Member = None, + size: int = 7, + ) -> None: + + self.bot = bot + self.channel = channel + self.player1 = player1 + self.player2 = player2 or AI(game=self) + + self.grid = self.generate_board(size) + self.grid_size = size + + self.unicode_numbers = UNICODE_NUMBERS[:self.grid_size] + + self.message = None + + self.turn = None + self.next = None + + @staticmethod + def generate_board(size: int) -> typing.List[typing.List[int]]: + """Generate the connect 4 board.""" + return [[0 for _ in range(size)] for _ in range(size)] + + async def print_grid(self) -> None: + """Formats and outputs the Connect Four grid to the channel.""" + rows = [" ".join(EMOJIS[s] for s in row) for row in self.grid] + first_row = " ".join(x for x in NUMBERS[:self.grid_size]) + formatted_grid = "\n".join([first_row] + rows) + embed = discord.Embed(title="Connect Four Board", description=formatted_grid) + + if self.message: + await self.message.edit(embed=embed) + else: + self.message = await self.channel.send(embed=embed) + for emoji in self.unicode_numbers: + await self.message.add_reaction(emoji) + + async def start_game(self) -> None: + """Begins the game.""" + self.turn, self.next = self.player1, self.player2 + + while True: + await self.print_grid() + if isinstance(self.turn, AI): + coords = self.turn.play() + else: + coords = await self.player_turn() + + if not coords: + return + + if self.check_win(coords, 1 if self.turn == self.player1 else 2): + if isinstance(self.turn, AI): + await self.channel.send(f"Game Over! {self.turn.mention} lost against AI") + else: + if isinstance(self.next, AI): + await self.channel.send(f"Game Over! {self.turn.mention} won against AI") + else: + await self.channel.send(f"Game Over! {self.turn.mention} won against {self.next.mention}") + await self.print_grid() + return + + self.turn, self.next = self.next, self.turn + + def predicate(self, reaction: discord.Reaction, user: discord.Member) -> bool: + """The predicate to check for the player's reaction.""" + return ( + reaction.message.id == self.message.id + and user.id == self.turn.id + and str(reaction.emoji) in self.unicode_numbers + ) + + async def player_turn(self) -> Coordinate: + """Initiate the player's turn.""" + message = await self.channel.send( + f"{self.turn.mention}, it's your turn! React with a column you want to place your token" + ) + player_num = 1 if self.turn == self.player1 else 2 + while True: + full_column = False + try: + reaction, user = await self.bot.wait_for("reaction_add", check=self.predicate, timeout=30.0) + except asyncio.TimeoutError: + await self.channel.send(f"{self.turn.mention}, you took too long. Game over!") + return + else: + await message.delete() + await self.message.remove_reaction(reaction, user) + column_num = self.unicode_numbers.index(str(reaction.emoji)) + + column = [row[column_num] for row in self.grid] + + for row_num, square in reversed(list(enumerate(column))): + if not square: + self.grid[row_num][column_num] = player_num + coords = row_num, column_num + break + else: + await self.channel.send(f"Column {column_num + 1} is full. Try again") + full_column = True + if not full_column: + break + return coords + + def check_win(self, coords: Coordinate, player_num: int) -> bool: + """Check that placing a counter here would cause the player to win.""" + vertical = [(-1, 0), (1, 0)] + horizontal = [(0, 1), (0, -1)] + forward_diag = [(-1, 1), (1, -1)] + backward_diag = [(-1, -1), (1, 1)] + axes = [vertical, horizontal, forward_diag, backward_diag] + + for axis in axes: + in_a_row = 1 # The initial counter that is compared to + for (row_incr, column_incr) in axis: + row, column = coords + row += row_incr + column += column_incr + + while 0 <= row < self.grid_size and 0 <= column < self.grid_size: + if self.grid[row][column] == player_num: + in_a_row += 1 + row += row_incr + column += column_incr + else: + break + if in_a_row >= 4: + return True + return False + + +class AI: + """The Computer Player for Single-Player games.""" + + def __init__(self, game: Game) -> None: + self.game = game + + def get_possible_places(self) -> typing.List[Coordinate]: + """Gets all the coordinates where the AI could possibly place a counter.""" + possible_coords = [] + for column_num in range(self.game.grid_size): + column = [row[column_num] for row in self.game.grid] + for row_num, square in reversed(list(enumerate(column))): + if not square: + possible_coords.append((row_num, column_num)) + break + return possible_coords + + def check_ai_win(self, coord_list: typing.List[Coordinate]) -> typing.Optional[Coordinate]: + """Check if placing a counter in any possible coordinate would cause the AI to win.""" + if random.randint(1, 10) == 1: # 10% chance of not winning + return + for coords in coord_list: + if self.game.check_win(coords, 2): + return coords + + def check_player_win(self, coord_list: typing.List[Coordinate]) -> typing.Optional[Coordinate]: + """Check if placing a counter in any possible coordinate would stop the player from winning.""" + if random.randint(1, 4) == 1: # 25% chance of not blocking the player + return + for coords in coord_list: + if self.game.check_win(coords, 1): + return coords + + @staticmethod + def random_coords(coord_list: typing.List[Coordinate]) -> Coordinate: + """Picks a random coordinate from the possible ones.""" + return random.choice(coord_list) + + def play(self) -> Coordinate: + """The AI's turn.""" + possible_coords = self.get_possible_places() + + coords = self.check_ai_win(possible_coords) # Win + if not coords: + coords = self.check_player_win(possible_coords) # Try to stop P1 from winning + if not coords: + coords = self.random_coords(possible_coords) + + row, column = coords + self.game.grid[row][column] = 2 + return coords + + +class ConnectFour(commands.Cog): + """Connect Four. The Classic Vertical Four-in-a-row Game!""" + + def __init__(self, bot: commands.Bot) -> None: + self.bot = bot + self.games: typing.List[Game] = [] + self.waiting: typing.List[discord.Member] = [] + + self.max_board_size = 9 + self.min_board_size = 5 + + def get_player( + self, + ctx: commands.Context, + announcement: discord.Message, + reaction: discord.Reaction, + user: discord.Member + ) -> bool: + """Predicate checking the criteria for the announcement message.""" + if self.already_playing(ctx.author): # If they've joined a game since requesting a player 2 + return True # Is dealt with later on + if ( + user.id not in (ctx.me.id, ctx.author.id) + and str(reaction.emoji) == HAND_RAISED_EMOJI + and reaction.message.id == announcement.id + ): + if self.already_playing(user): + self.bot.loop.create_task(ctx.send(f"{user.mention} You're already playing a game!")) + self.bot.loop.create_task(announcement.remove_reaction(reaction, user)) + return False + + if user in self.waiting: + self.bot.loop.create_task(ctx.send( + f"{user.mention} Please cancel your game first before joining another one." + )) + self.bot.loop.create_task(announcement.remove_reaction(reaction, user)) + return False + + return True + + if ( + user.id == ctx.author.id + and str(reaction.emoji) == CROSS_EMOJI + and reaction.message.id == announcement.id + ): + return True + return False + + def already_playing(self, player: discord.Member) -> bool: + """Check if someone is already in a game.""" + return any(player in (game.player1, game.player2) for game in self.games) + + async def _play_game(self, ctx: commands.Context, user: typing.Optional[discord.Member], board_size: int) -> None: + """Helper for playing a game of connect four.""" + try: + game = Game(self.bot, ctx.channel, ctx.author, user, size=board_size) + self.games.append(game) + await game.start_game() + self.games.remove(game) + except Exception: + # End the game in the event of an unforseen error so the players aren't stuck in a game + await ctx.send(f"{ctx.author.mention} {user.mention if user else ''} An error occurred. Game failed") + self.games.remove(game) + raise + + @commands.group(invoke_without_command=True, aliases=[ + "4inarow", "4-in-a-row", "4_in_a_row", "connect4", "connect-four", "connect_four" + ]) + @commands.guild_only() + async def connectfour(self, ctx: commands.Context, board_size: int = 7) -> None: + """ + Play the classic game of Connect Four with someone! + + Sets up a message waiting for someone else to react and play along. + The game will start once someone has reacted. + All inputs will be through reactions. + """ + if self.already_playing(ctx.author): + await ctx.send("You're already playing a game!") + return + + if ctx.author in self.waiting: + await ctx.send("You've already sent out a request for a player 2") + return + + if board_size > self.max_board_size or board_size < self.min_board_size: + await ctx.send(f"{board_size} is not a valid board size. A valid board size it " + f"between `{self.min_board_size}` to `{self.max_board_size}`") + return + + announcement = await ctx.send( + "**Connect Four**: A new game is about to start!\n" + f"Press {HAND_RAISED_EMOJI} to play against {ctx.author.mention}!\n" + f"(Cancel the game with {CROSS_EMOJI}.)" + ) + self.waiting.append(ctx.author) + await announcement.add_reaction(HAND_RAISED_EMOJI) + await announcement.add_reaction(CROSS_EMOJI) + + try: + reaction, user = await self.bot.wait_for( + "reaction_add", + check=partial(self.get_player, ctx, announcement), + timeout=60.0 + ) + except asyncio.TimeoutError: + self.waiting.remove(ctx.author) + await announcement.delete() + await ctx.send(f"{ctx.author.mention} Seems like there's no one here to play" + f"Use `{ctx.prefix}{ctx.invoked_with} ai` to play against a computer." + ) + return + + if str(reaction.emoji) == CROSS_EMOJI: + self.waiting.remove(ctx.author) + await announcement.delete() + await ctx.send(f"{ctx.author.mention} Game cancelled.") + return + + await announcement.delete() + self.waiting.remove(ctx.author) + if self.already_playing(ctx.author): + return + + await self._play_game(ctx, user, board_size) + + @connectfour.command(aliases=["AI", "CPU", "computer", "cpu", "Computer"]) + async def ai(self, ctx: commands.Context, board_size: int = 7) -> None: + """Play Connect Four against a computer player.""" + if self.already_playing(ctx.author): + await ctx.send("You're already playing a game!") + return + + if ctx.author in self.waiting: + await ctx.send("You've already sent out a request for a player 2") + return + + if board_size > self.max_board_size or board_size < self.min_board_size: + await ctx.send(f"{board_size} is not a valid board size. A valid board size it " + f"between `{self.min_board_size}` to `{self.max_board_size}`") + return + + await self._play_game(ctx, user=None, board_size=board_size) + + +def setup(bot: commands.Bot) -> None: + """Load ConnectFour Cog.""" + bot.add_cog(ConnectFour(bot)) -- cgit v1.2.3 From f44a39ddc14ee23dd9394deac4a90cf0300ebbab Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Wed, 20 Jan 2021 05:28:10 +0530 Subject: fix grammar and spacing --- bot/exts/evergreen/connect_four.py | 62 ++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 30 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/connect_four.py b/bot/exts/evergreen/connect_four.py index 9519f124..2592bf3f 100644 --- a/bot/exts/evergreen/connect_four.py +++ b/bot/exts/evergreen/connect_four.py @@ -58,8 +58,8 @@ class Game: self.message = None - self.turn = None - self.next = None + self.player_active = None + self.player_inactive = None @staticmethod def generate_board(size: int) -> typing.List[typing.List[int]]: @@ -82,51 +82,51 @@ class Game: async def start_game(self) -> None: """Begins the game.""" - self.turn, self.next = self.player1, self.player2 + self.player_active, self.player_inactive = self.player1, self.player2 while True: await self.print_grid() - if isinstance(self.turn, AI): - coords = self.turn.play() + if isinstance(self.player_active, AI): + coords = self.player_active.play() else: coords = await self.player_turn() if not coords: return - if self.check_win(coords, 1 if self.turn == self.player1 else 2): - if isinstance(self.turn, AI): - await self.channel.send(f"Game Over! {self.turn.mention} lost against AI") + if self.check_win(coords, 1 if self.player_active == self.player1 else 2): + if isinstance(self.player_active, AI): + await self.channel.send(f"Game Over! {self.player_active.mention} lost against AI") else: - if isinstance(self.next, AI): - await self.channel.send(f"Game Over! {self.turn.mention} won against AI") + if isinstance(self.player_inactive, AI): + await self.channel.send(f"Game Over! {self.player_active.mention} won against AI") else: - await self.channel.send(f"Game Over! {self.turn.mention} won against {self.next.mention}") + await self.channel.send(f"Game Over! {self.player_active.mention} won against {self.player_inactive.mention}") await self.print_grid() return - self.turn, self.next = self.next, self.turn + self.player_active, self.player_inactive = self.player_inactive, self.player_active def predicate(self, reaction: discord.Reaction, user: discord.Member) -> bool: """The predicate to check for the player's reaction.""" return ( reaction.message.id == self.message.id - and user.id == self.turn.id + and user.id == self.player_active.id and str(reaction.emoji) in self.unicode_numbers ) async def player_turn(self) -> Coordinate: """Initiate the player's turn.""" message = await self.channel.send( - f"{self.turn.mention}, it's your turn! React with a column you want to place your token" + f"{self.turn.mention}, it's your turn! React with the column you want to place your token in." ) - player_num = 1 if self.turn == self.player1 else 2 + player_num = 1 if self.player_active == self.player1 else 2 while True: full_column = False try: reaction, user = await self.bot.wait_for("reaction_add", check=self.predicate, timeout=30.0) except asyncio.TimeoutError: - await self.channel.send(f"{self.turn.mention}, you took too long. Game over!") + await self.channel.send(f"{self.player_active.mention}, you took too long. Game over!") return else: await message.delete() @@ -156,7 +156,7 @@ class Game: axes = [vertical, horizontal, forward_diag, backward_diag] for axis in axes: - in_a_row = 1 # The initial counter that is compared to + counters_in_a_row = 1 # The initial counter that is compared to for (row_incr, column_incr) in axis: row, column = coords row += row_incr @@ -164,12 +164,12 @@ class Game: while 0 <= row < self.grid_size and 0 <= column < self.grid_size: if self.grid[row][column] == player_num: - in_a_row += 1 + counters_in_a_row += 1 row += row_incr column += column_incr else: break - if in_a_row >= 4: + if counters_in_a_row >= 4: return True return False @@ -287,16 +287,17 @@ class ConnectFour(commands.Cog): await game.start_game() self.games.remove(game) except Exception: - # End the game in the event of an unforseen error so the players aren't stuck in a game + # End the game in the event of an unforeseen error so the players aren't stuck in a game await ctx.send(f"{ctx.author.mention} {user.mention if user else ''} An error occurred. Game failed") self.games.remove(game) raise - @commands.group(invoke_without_command=True, aliases=[ - "4inarow", "4-in-a-row", "4_in_a_row", "connect4", "connect-four", "connect_four" - ]) + @commands.group( + invoke_without_command=True, + aliases=["4inarow", "connect4", "connectfour", "c4"] + ) @commands.guild_only() - async def connectfour(self, ctx: commands.Context, board_size: int = 7) -> None: + async def connect_four(self, ctx: commands.Context, board_size: int = 7) -> None: """ Play the classic game of Connect Four with someone! @@ -313,8 +314,8 @@ class ConnectFour(commands.Cog): return if board_size > self.max_board_size or board_size < self.min_board_size: - await ctx.send(f"{board_size} is not a valid board size. A valid board size it " - f"between `{self.min_board_size}` to `{self.max_board_size}`") + await ctx.send(f"{board_size} is not a valid board size. A valid board size is " + f"between `{self.min_board_size}` and `{self.max_board_size}`.") return announcement = await ctx.send( @@ -335,9 +336,10 @@ class ConnectFour(commands.Cog): except asyncio.TimeoutError: self.waiting.remove(ctx.author) await announcement.delete() - await ctx.send(f"{ctx.author.mention} Seems like there's no one here to play" - f"Use `{ctx.prefix}{ctx.invoked_with} ai` to play against a computer." - ) + await ctx.send( + f"{ctx.author.mention} Seems like there's no one here to play. " + f"Use `{ctx.prefix}{ctx.invoked_with} ai` to play against a computer." + ) return if str(reaction.emoji) == CROSS_EMOJI: @@ -353,7 +355,7 @@ class ConnectFour(commands.Cog): await self._play_game(ctx, user, board_size) - @connectfour.command(aliases=["AI", "CPU", "computer", "cpu", "Computer"]) + @connectfour.command(aliases=["bot", "computer", "cpu"]) async def ai(self, ctx: commands.Context, board_size: int = 7) -> None: """Play Connect Four against a computer player.""" if self.already_playing(ctx.author): -- cgit v1.2.3 From 24e7f9508b61675d17f8fabf58f2fef4e7f97084 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Wed, 20 Jan 2021 05:45:26 +0530 Subject: COrrect annotations and improve docstrings ; make code more pythonic --- bot/exts/evergreen/connect_four.py | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/connect_four.py b/bot/exts/evergreen/connect_four.py index 2592bf3f..1d2c82a2 100644 --- a/bot/exts/evergreen/connect_four.py +++ b/bot/exts/evergreen/connect_four.py @@ -42,7 +42,7 @@ class Game: bot: commands.Bot, channel: discord.TextChannel, player1: discord.Member, - player2: discord.Member = None, + player2: typing.Optional[discord.Member], size: int = 7, ) -> None: @@ -64,7 +64,7 @@ class Game: @staticmethod def generate_board(size: int) -> typing.List[typing.List[int]]: """Generate the connect 4 board.""" - return [[0 for _ in range(size)] for _ in range(size)] + return [[0]*size]*size async def print_grid(self) -> None: """Formats and outputs the Connect Four grid to the channel.""" @@ -101,7 +101,9 @@ class Game: if isinstance(self.player_inactive, AI): await self.channel.send(f"Game Over! {self.player_active.mention} won against AI") else: - await self.channel.send(f"Game Over! {self.player_active.mention} won against {self.player_inactive.mention}") + await self.channel.send( + f"Game Over! {self.player_active.mention} won against {self.player_inactive.mention}" + ) await self.print_grid() return @@ -213,14 +215,22 @@ class AI: return random.choice(coord_list) def play(self) -> Coordinate: - """The AI's turn.""" + """ + Plays for the AI. + + Gets all possible coords, and determins the move: + 1. coords where it can win. + 2. coords where the player can win. + 3. Random coord + The first possible value is choosen. + """ possible_coords = self.get_possible_places() - coords = self.check_ai_win(possible_coords) # Win - if not coords: - coords = self.check_player_win(possible_coords) # Try to stop P1 from winning - if not coords: - coords = self.random_coords(possible_coords) + coords = ( + self.check_ai_win(possible_coords) + or self.check_player_win(possible_coords) + or self.random_coords(possible_coords) + ) row, column = coords self.game.grid[row][column] = 2 @@ -296,7 +306,6 @@ class ConnectFour(commands.Cog): invoke_without_command=True, aliases=["4inarow", "connect4", "connectfour", "c4"] ) - @commands.guild_only() async def connect_four(self, ctx: commands.Context, board_size: int = 7) -> None: """ Play the classic game of Connect Four with someone! @@ -313,7 +322,7 @@ class ConnectFour(commands.Cog): await ctx.send("You've already sent out a request for a player 2") return - if board_size > self.max_board_size or board_size < self.min_board_size: + if not self.min_board_size <= board_size <= self.max_board_size: await ctx.send(f"{board_size} is not a valid board size. A valid board size is " f"between `{self.min_board_size}` and `{self.max_board_size}`.") return @@ -355,7 +364,7 @@ class ConnectFour(commands.Cog): await self._play_game(ctx, user, board_size) - @connectfour.command(aliases=["bot", "computer", "cpu"]) + @connect_four.command(aliases=["bot", "computer", "cpu"]) async def ai(self, ctx: commands.Context, board_size: int = 7) -> None: """Play Connect Four against a computer player.""" if self.already_playing(ctx.author): -- cgit v1.2.3 From d1acfa3ecc37b63b21a1889d38ae1405b917238f Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Wed, 20 Jan 2021 07:02:08 +0530 Subject: Change Ai to bot's user and add stop game functionality, remove redundant code, and DRY --- bot/exts/evergreen/connect_four.py | 68 ++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 29 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/connect_four.py b/bot/exts/evergreen/connect_four.py index 1d2c82a2..1e5d6fac 100644 --- a/bot/exts/evergreen/connect_four.py +++ b/bot/exts/evergreen/connect_four.py @@ -49,7 +49,7 @@ class Game: self.bot = bot self.channel = channel self.player1 = player1 - self.player2 = player2 or AI(game=self) + self.player2 = player2 or AI(self.bot, game=self) self.grid = self.generate_board(size) self.grid_size = size @@ -64,7 +64,7 @@ class Game: @staticmethod def generate_board(size: int) -> typing.List[typing.List[int]]: """Generate the connect 4 board.""" - return [[0]*size]*size + return [[0 for _ in range(size)] for _ in range(size)] async def print_grid(self) -> None: """Formats and outputs the Connect Four grid to the channel.""" @@ -79,6 +79,7 @@ class Game: self.message = await self.channel.send(embed=embed) for emoji in self.unicode_numbers: await self.message.add_reaction(emoji) + await self.message.add_reaction(CROSS_EMOJI) async def start_game(self) -> None: """Begins the game.""" @@ -96,10 +97,12 @@ class Game: if self.check_win(coords, 1 if self.player_active == self.player1 else 2): if isinstance(self.player_active, AI): - await self.channel.send(f"Game Over! {self.player_active.mention} lost against AI") + await self.channel.send(f"Game Over! {self.player_inactive.mention} lost against" + f" {self.bot.user.mention}") else: if isinstance(self.player_inactive, AI): - await self.channel.send(f"Game Over! {self.player_active.mention} won against AI") + await self.channel.send(f"Game Over! {self.player_active.mention} won against" + f" {self.bot.user.mention}") else: await self.channel.send( f"Game Over! {self.player_active.mention} won against {self.player_inactive.mention}" @@ -114,13 +117,13 @@ class Game: return ( reaction.message.id == self.message.id and user.id == self.player_active.id - and str(reaction.emoji) in self.unicode_numbers + and str(reaction.emoji) in (*self.unicode_numbers, CROSS_EMOJI) ) async def player_turn(self) -> Coordinate: """Initiate the player's turn.""" message = await self.channel.send( - f"{self.turn.mention}, it's your turn! React with the column you want to place your token in." + f"{self.player_active.mention}, it's your turn! React with the column you want to place your token in." ) player_num = 1 if self.player_active == self.player1 else 2 while True: @@ -131,6 +134,13 @@ class Game: await self.channel.send(f"{self.player_active.mention}, you took too long. Game over!") return else: + if str(reaction.emoji) == CROSS_EMOJI: + await message.delete() + await self.channel.send( + f"{user.mention} has abandoned the game :(" + ) + return + await message.delete() await self.message.remove_reaction(reaction, user) column_num = self.unicode_numbers.index(str(reaction.emoji)) @@ -179,8 +189,9 @@ class Game: class AI: """The Computer Player for Single-Player games.""" - def __init__(self, game: Game) -> None: + def __init__(self, bot: commands.Bot, game: Game) -> None: self.game = game + self.mention = bot.user.mention def get_possible_places(self) -> typing.List[Coordinate]: """Gets all the coordinates where the AI could possibly place a counter.""" @@ -248,6 +259,23 @@ class ConnectFour(commands.Cog): self.max_board_size = 9 self.min_board_size = 5 + async def check_author(self, ctx: commands.Context, board_size: int) -> bool: + """Check if the requester is free and the board size is correct.""" + if self.already_playing(ctx.author): + await ctx.send("You're already playing a game!") + return False + + if ctx.author in self.waiting: + await ctx.send("You've already sent out a request for a player 2") + return False + + if not self.min_board_size <= board_size <= self.max_board_size: + await ctx.send(f"{board_size} is not a valid board size. A valid board size is " + f"between `{self.min_board_size}` and `{self.max_board_size}`.") + return False + + return True + def get_player( self, ctx: commands.Context, @@ -314,17 +342,8 @@ class ConnectFour(commands.Cog): The game will start once someone has reacted. All inputs will be through reactions. """ - if self.already_playing(ctx.author): - await ctx.send("You're already playing a game!") - return - - if ctx.author in self.waiting: - await ctx.send("You've already sent out a request for a player 2") - return - - if not self.min_board_size <= board_size <= self.max_board_size: - await ctx.send(f"{board_size} is not a valid board size. A valid board size is " - f"between `{self.min_board_size}` and `{self.max_board_size}`.") + check_author_result = await self.check_author(ctx, board_size) + if not check_author_result: return announcement = await ctx.send( @@ -367,17 +386,8 @@ class ConnectFour(commands.Cog): @connect_four.command(aliases=["bot", "computer", "cpu"]) async def ai(self, ctx: commands.Context, board_size: int = 7) -> None: """Play Connect Four against a computer player.""" - if self.already_playing(ctx.author): - await ctx.send("You're already playing a game!") - return - - if ctx.author in self.waiting: - await ctx.send("You've already sent out a request for a player 2") - return - - if board_size > self.max_board_size or board_size < self.min_board_size: - await ctx.send(f"{board_size} is not a valid board size. A valid board size it " - f"between `{self.min_board_size}` to `{self.max_board_size}`") + check_author_result = await self.check_author(ctx, board_size) + if not check_author_result: return await self._play_game(ctx, user=None, board_size=board_size) -- cgit v1.2.3 From dd8664c3b4ff8037b9e28d9935a2f99fe9463a7b Mon Sep 17 00:00:00 2001 From: soul crusher 2005 Date: Wed, 20 Jan 2021 16:18:43 +0530 Subject: Update trivia_quiz.json new questions --- bot/resources/evergreen/trivia_quiz.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'bot') diff --git a/bot/resources/evergreen/trivia_quiz.json b/bot/resources/evergreen/trivia_quiz.json index 8f0a4114..a5e3a3e4 100644 --- a/bot/resources/evergreen/trivia_quiz.json +++ b/bot/resources/evergreen/trivia_quiz.json @@ -247,6 +247,18 @@ "question": "What is the capital of Iraq?", "answer": "Baghdad", "info": "Baghdad is the capital of Iraq. It has a population of 7 million people." + }, + { + "id": 136, + "question":"The United Nations headquarters is located at which city?", + "answer":"New York", + "info":"The United Nations is headquartered in New York City in a complex designed by a board of architects led by Wallace Harrison and built by the architectural firm Harrison & Abramovitz. The complex has served as the official headquarters of the United Nations since its completion in 1951." + }, + { + "id": 137, + "question":"At what year did Christopher Columbus discover America?", + "answer":"1492", + "info":"The explorer Christopher Columbus made four trips across the Atlantic Ocean from Spain: in 1492, 1493, 1498 and 1502. He was determined to find a direct water route west from Europe to Asia, but he never did. Instead, he stumbled upon the Americas" } ] } -- cgit v1.2.3 From 46e594c390cce07f522329b5fc012b886bcdbb81 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Thu, 21 Jan 2021 07:40:53 +0530 Subject: Add loading message before finishing all reactions and improve embed title --- bot/exts/evergreen/connect_four.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/connect_four.py b/bot/exts/evergreen/connect_four.py index 1e5d6fac..a4f29172 100644 --- a/bot/exts/evergreen/connect_four.py +++ b/bot/exts/evergreen/connect_four.py @@ -68,18 +68,24 @@ class Game: async def print_grid(self) -> None: """Formats and outputs the Connect Four grid to the channel.""" + title = ( + f'Connect 4: {self.player1.display_name}' + f'VS {self.player2.display_name}' + ) + rows = [" ".join(EMOJIS[s] for s in row) for row in self.grid] first_row = " ".join(x for x in NUMBERS[:self.grid_size]) formatted_grid = "\n".join([first_row] + rows) - embed = discord.Embed(title="Connect Four Board", description=formatted_grid) + embed = discord.Embed(title=title, description=formatted_grid) if self.message: await self.message.edit(embed=embed) else: - self.message = await self.channel.send(embed=embed) + self.message = await self.channel.send(content='Loading ....') for emoji in self.unicode_numbers: await self.message.add_reaction(emoji) await self.message.add_reaction(CROSS_EMOJI) + await self.message.edit(content=None, embed=embed) async def start_game(self) -> None: """Begins the game.""" -- cgit v1.2.3 From 089baf161da449995b475971c5e0689a5b24c7e8 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Thu, 21 Jan 2021 09:59:11 +0530 Subject: Improve embeds and docstrings --- bot/exts/evergreen/connect_four.py | 58 +++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 23 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/connect_four.py b/bot/exts/evergreen/connect_four.py index a4f29172..38647f8e 100644 --- a/bot/exts/evergreen/connect_four.py +++ b/bot/exts/evergreen/connect_four.py @@ -38,12 +38,12 @@ class Game: """A Connect 4 Game.""" def __init__( - self, - bot: commands.Bot, - channel: discord.TextChannel, - player1: discord.Member, - player2: typing.Optional[discord.Member], - size: int = 7, + self, + bot: commands.Bot, + channel: discord.TextChannel, + player1: discord.Member, + player2: typing.Optional[discord.Member], + size: int = 7, ) -> None: self.bot = bot @@ -70,7 +70,7 @@ class Game: """Formats and outputs the Connect Four grid to the channel.""" title = ( f'Connect 4: {self.player1.display_name}' - f'VS {self.player2.display_name}' + f'VS {self.bot.user.display_name if isinstance(self.player2, AI) else self.player2.display_name}' ) rows = [" ".join(EMOJIS[s] for s in row) for row in self.grid] @@ -211,16 +211,26 @@ class AI: return possible_coords def check_ai_win(self, coord_list: typing.List[Coordinate]) -> typing.Optional[Coordinate]: - """Check if placing a counter in any possible coordinate would cause the AI to win.""" - if random.randint(1, 10) == 1: # 10% chance of not winning + """ + Check AI win. + + Check if placing a counter in any possible coordinate would cause the AI to win + with 10% chance of not winning and returning None + """ + if random.randint(1, 10) == 1: return for coords in coord_list: if self.game.check_win(coords, 2): return coords def check_player_win(self, coord_list: typing.List[Coordinate]) -> typing.Optional[Coordinate]: - """Check if placing a counter in any possible coordinate would stop the player from winning.""" - if random.randint(1, 4) == 1: # 25% chance of not blocking the player + """ + Check Player win. + + Check if placing a counter in possible coordinates would stop the player + from winning with 25% of not blocking them and returning None. + """ + if random.randint(1, 4) == 1: return for coords in coord_list: if self.game.check_win(coords, 1): @@ -283,19 +293,20 @@ class ConnectFour(commands.Cog): return True def get_player( - self, - ctx: commands.Context, - announcement: discord.Message, - reaction: discord.Reaction, - user: discord.Member + self, + ctx: commands.Context, + announcement: discord.Message, + reaction: discord.Reaction, + user: discord.Member ) -> bool: """Predicate checking the criteria for the announcement message.""" if self.already_playing(ctx.author): # If they've joined a game since requesting a player 2 return True # Is dealt with later on + if ( - user.id not in (ctx.me.id, ctx.author.id) - and str(reaction.emoji) == HAND_RAISED_EMOJI - and reaction.message.id == announcement.id + user.id not in (ctx.me.id, ctx.author.id) + and str(reaction.emoji) == HAND_RAISED_EMOJI + and reaction.message.id == announcement.id ): if self.already_playing(user): self.bot.loop.create_task(ctx.send(f"{user.mention} You're already playing a game!")) @@ -312,9 +323,9 @@ class ConnectFour(commands.Cog): return True if ( - user.id == ctx.author.id - and str(reaction.emoji) == CROSS_EMOJI - and reaction.message.id == announcement.id + user.id == ctx.author.id + and str(reaction.emoji) == CROSS_EMOJI + and reaction.message.id == announcement.id ): return True return False @@ -333,7 +344,8 @@ class ConnectFour(commands.Cog): except Exception: # End the game in the event of an unforeseen error so the players aren't stuck in a game await ctx.send(f"{ctx.author.mention} {user.mention if user else ''} An error occurred. Game failed") - self.games.remove(game) + if game in self.games: + self.games.remove(game) raise @commands.group( -- cgit v1.2.3 From a972cd19e993e5ea9a1120432d7523329cb22d9b Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Thu, 21 Jan 2021 11:32:41 +0530 Subject: Add ability to get custom tokens from the bot --- bot/exts/evergreen/connect_four.py | 67 +++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 23 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/connect_four.py b/bot/exts/evergreen/connect_four.py index 38647f8e..6ae14f53 100644 --- a/bot/exts/evergreen/connect_four.py +++ b/bot/exts/evergreen/connect_four.py @@ -6,7 +6,7 @@ from functools import partial import discord from discord.ext import commands -EMOJIS = [":white_circle:", ":blue_circle:", ":red_circle:"] +EMOJIS = None NUMBERS = [ ":one:", ":two:", @@ -38,12 +38,12 @@ class Game: """A Connect 4 Game.""" def __init__( - self, - bot: commands.Bot, - channel: discord.TextChannel, - player1: discord.Member, - player2: typing.Optional[discord.Member], - size: int = 7, + self, + bot: commands.Bot, + channel: discord.TextChannel, + player1: discord.Member, + player2: typing.Optional[discord.Member], + size: int = 7, ) -> None: self.bot = bot @@ -293,20 +293,20 @@ class ConnectFour(commands.Cog): return True def get_player( - self, - ctx: commands.Context, - announcement: discord.Message, - reaction: discord.Reaction, - user: discord.Member + self, + ctx: commands.Context, + announcement: discord.Message, + reaction: discord.Reaction, + user: discord.Member ) -> bool: """Predicate checking the criteria for the announcement message.""" if self.already_playing(ctx.author): # If they've joined a game since requesting a player 2 return True # Is dealt with later on if ( - user.id not in (ctx.me.id, ctx.author.id) - and str(reaction.emoji) == HAND_RAISED_EMOJI - and reaction.message.id == announcement.id + user.id not in (ctx.me.id, ctx.author.id) + and str(reaction.emoji) == HAND_RAISED_EMOJI + and reaction.message.id == announcement.id ): if self.already_playing(user): self.bot.loop.create_task(ctx.send(f"{user.mention} You're already playing a game!")) @@ -323,9 +323,9 @@ class ConnectFour(commands.Cog): return True if ( - user.id == ctx.author.id - and str(reaction.emoji) == CROSS_EMOJI - and reaction.message.id == announcement.id + user.id == ctx.author.id + and str(reaction.emoji) == CROSS_EMOJI + and reaction.message.id == announcement.id ): return True return False @@ -334,9 +334,18 @@ class ConnectFour(commands.Cog): """Check if someone is already in a game.""" return any(player in (game.player1, game.player2) for game in self.games) - async def _play_game(self, ctx: commands.Context, user: typing.Optional[discord.Member], board_size: int) -> None: + async def _play_game( + self, + ctx: commands.Context, + user: typing.Optional[discord.Member], + board_size: int, + emoji1: str, + emoji2: str + ) -> None: """Helper for playing a game of connect four.""" try: + global EMOJIS + EMOJIS = [":white_circle:", str(emoji1), str(emoji2)] game = Game(self.bot, ctx.channel, ctx.author, user, size=board_size) self.games.append(game) await game.start_game() @@ -352,7 +361,13 @@ class ConnectFour(commands.Cog): invoke_without_command=True, aliases=["4inarow", "connect4", "connectfour", "c4"] ) - async def connect_four(self, ctx: commands.Context, board_size: int = 7) -> None: + async def connect_four( + self, + ctx: commands.Context, + board_size: int = 7, + emoji1: str = ":blue_circle:", + emoji2: str = ":red_circle:" + ) -> None: """ Play the classic game of Connect Four with someone! @@ -399,16 +414,22 @@ class ConnectFour(commands.Cog): if self.already_playing(ctx.author): return - await self._play_game(ctx, user, board_size) + await self._play_game(ctx, user, board_size, emoji1, emoji2) @connect_four.command(aliases=["bot", "computer", "cpu"]) - async def ai(self, ctx: commands.Context, board_size: int = 7) -> None: + async def ai( + self, + ctx: commands.Context, + board_size: int = 7, + emoji1: str = ":blue_circle:", + emoji2: str = ":red_circle:" + ) -> None: """Play Connect Four against a computer player.""" check_author_result = await self.check_author(ctx, board_size) if not check_author_result: return - await self._play_game(ctx, user=None, board_size=board_size) + await self._play_game(ctx, None, board_size, emoji1, emoji2) def setup(bot: commands.Bot) -> None: -- cgit v1.2.3 From 8175bc0fbe1fad08372a27b1fb340baf8f20062b Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Thu, 21 Jan 2021 14:01:45 +0530 Subject: Remove redundant code --- bot/exts/evergreen/connect_four.py | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/connect_four.py b/bot/exts/evergreen/connect_four.py index 6ae14f53..e6d4b41a 100644 --- a/bot/exts/evergreen/connect_four.py +++ b/bot/exts/evergreen/connect_four.py @@ -133,7 +133,6 @@ class Game: ) player_num = 1 if self.player_active == self.player1 else 2 while True: - full_column = False try: reaction, user = await self.bot.wait_for("reaction_add", check=self.predicate, timeout=30.0) except asyncio.TimeoutError: @@ -149,21 +148,15 @@ class Game: await message.delete() await self.message.remove_reaction(reaction, user) - column_num = self.unicode_numbers.index(str(reaction.emoji)) + column_num = self.unicode_numbers.index(str(reaction.emoji)) column = [row[column_num] for row in self.grid] for row_num, square in reversed(list(enumerate(column))): if not square: self.grid[row_num][column_num] = player_num - coords = row_num, column_num - break - else: - await self.channel.send(f"Column {column_num + 1} is full. Try again") - full_column = True - if not full_column: - break - return coords + return row_num, column_num + message = await self.channel.send(f"Column {column_num + 1} is full. Try again") def check_win(self, coords: Coordinate, player_num: int) -> bool: """Check that placing a counter here would cause the player to win.""" -- cgit v1.2.3 From 35b2984674c3a1645476a8c2172deadd51472f0f Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Thu, 21 Jan 2021 14:14:15 +0530 Subject: Check if the emoji given by user is available --- bot/exts/evergreen/connect_four.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/connect_four.py b/bot/exts/evergreen/connect_four.py index e6d4b41a..a44d6dbf 100644 --- a/bot/exts/evergreen/connect_four.py +++ b/bot/exts/evergreen/connect_four.py @@ -358,8 +358,8 @@ class ConnectFour(commands.Cog): self, ctx: commands.Context, board_size: int = 7, - emoji1: str = ":blue_circle:", - emoji2: str = ":red_circle:" + emoji1: discord.Emoji = ":blue_circle:", + emoji2: discord.Emoji = ":red_circle:" ) -> None: """ Play the classic game of Connect Four with someone! @@ -407,6 +407,9 @@ class ConnectFour(commands.Cog): if self.already_playing(ctx.author): return + emoji1 = str(emoji1) + emoji2 = str(emoji2) + await self._play_game(ctx, user, board_size, emoji1, emoji2) @connect_four.command(aliases=["bot", "computer", "cpu"]) @@ -414,14 +417,17 @@ class ConnectFour(commands.Cog): self, ctx: commands.Context, board_size: int = 7, - emoji1: str = ":blue_circle:", - emoji2: str = ":red_circle:" + emoji1: discord.Emoji = ":blue_circle:", + emoji2: discord.Emoji = ":red_circle:" ) -> None: """Play Connect Four against a computer player.""" check_author_result = await self.check_author(ctx, board_size) if not check_author_result: return + emoji1 = str(emoji1) + emoji2 = str(emoji2) + await self._play_game(ctx, None, board_size, emoji1, emoji2) -- cgit v1.2.3 From db53775344e0ceef247fb0e045bc515c9d9591b8 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Sat, 23 Jan 2021 05:35:09 +0530 Subject: Fix user given emoji check --- bot/exts/evergreen/connect_four.py | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/connect_four.py b/bot/exts/evergreen/connect_four.py index a44d6dbf..be370a83 100644 --- a/bot/exts/evergreen/connect_four.py +++ b/bot/exts/evergreen/connect_four.py @@ -6,7 +6,7 @@ from functools import partial import discord from discord.ext import commands -EMOJIS = None +EMOJI_TOKENS = [":white_circle:", ":blue_circle:", ":red_circle:"] NUMBERS = [ ":one:", ":two:", @@ -32,6 +32,7 @@ UNICODE_NUMBERS = [ CROSS_EMOJI = "\u274e" HAND_RAISED_EMOJI = "\U0001f64b" Coordinate = typing.Optional[typing.Tuple[int, int]] +EMOJI_CHECK = typing.Union[discord.Emoji, str] class Game: @@ -336,9 +337,10 @@ class ConnectFour(commands.Cog): emoji2: str ) -> None: """Helper for playing a game of connect four.""" + global EMOJIS + EMOJIS = [":white_circle:", str(emoji1), str(emoji2)] + try: - global EMOJIS - EMOJIS = [":white_circle:", str(emoji1), str(emoji2)] game = Game(self.bot, ctx.channel, ctx.author, user, size=board_size) self.games.append(game) await game.start_game() @@ -358,8 +360,8 @@ class ConnectFour(commands.Cog): self, ctx: commands.Context, board_size: int = 7, - emoji1: discord.Emoji = ":blue_circle:", - emoji2: discord.Emoji = ":red_circle:" + emoji1: EMOJI_CHECK = ":blue_circle:", + emoji2: EMOJI_CHECK = ":red_circle:" ) -> None: """ Play the classic game of Connect Four with someone! @@ -368,6 +370,11 @@ class ConnectFour(commands.Cog): The game will start once someone has reacted. All inputs will be through reactions. """ + if isinstance(emoji1, str) and len(emoji1) > 1: + raise commands.EmojiNotFound(emoji1) + if isinstance(emoji2, str) and len(emoji2) > 1: + raise commands.EmojiNotFound(emoji2) + check_author_result = await self.check_author(ctx, board_size) if not check_author_result: return @@ -407,28 +414,22 @@ class ConnectFour(commands.Cog): if self.already_playing(ctx.author): return - emoji1 = str(emoji1) - emoji2 = str(emoji2) - - await self._play_game(ctx, user, board_size, emoji1, emoji2) + await self._play_game(ctx, user, board_size, str(emoji1), str(emoji2)) @connect_four.command(aliases=["bot", "computer", "cpu"]) async def ai( self, ctx: commands.Context, board_size: int = 7, - emoji1: discord.Emoji = ":blue_circle:", - emoji2: discord.Emoji = ":red_circle:" + emoji1: EMOJI_CHECK = ":blue_circle:" ) -> None: """Play Connect Four against a computer player.""" + if isinstance(emoji1, str) and len(emoji1) > 1: + raise commands.EmojiNotFound(emoji1) check_author_result = await self.check_author(ctx, board_size) if not check_author_result: return - - emoji1 = str(emoji1) - emoji2 = str(emoji2) - - await self._play_game(ctx, None, board_size, emoji1, emoji2) + await self._play_game(ctx, None, board_size, str(emoji1), ":red_circle:") def setup(bot: commands.Bot) -> None: -- cgit v1.2.3 From 9b62d84554fe8a27e3baef5e73eaac9127b2e54d Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Sat, 23 Jan 2021 17:39:51 +0530 Subject: Add ability to automatically send issues if matching # --- bot/exts/evergreen/issues.py | 96 +++++++++++++++++++++++++++++++------------- 1 file changed, 69 insertions(+), 27 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/issues.py b/bot/exts/evergreen/issues.py index e419a6f5..b701346c 100644 --- a/bot/exts/evergreen/issues.py +++ b/bot/exts/evergreen/issues.py @@ -1,5 +1,7 @@ import logging import random +import re +import typing as t import discord from discord.ext import commands @@ -13,9 +15,7 @@ BAD_RESPONSE = { 404: "Issue/pull request not located! Please enter a valid number!", 403: "Rate limit has been hit! Please try again later!" } - MAX_REQUESTS = 10 - REQUEST_HEADERS = dict() if GITHUB_TOKEN := Tokens.github: REQUEST_HEADERS["Authorization"] = f"token {GITHUB_TOKEN}" @@ -27,31 +27,19 @@ class Issues(commands.Cog): def __init__(self, bot: commands.Bot): self.bot = bot - @commands.command(aliases=("pr",)) - @override_in_channel(WHITELISTED_CHANNELS + (Channels.dev_contrib, Channels.dev_branding)) - async def issue( - self, - ctx: commands.Context, - numbers: commands.Greedy[int], - repository: str = "sir-lancebot", - user: str = "python-discord" - ) -> None: - """Command to retrieve issue(s) from a GitHub repository.""" + async def fetch_issues( + self, + numbers: set, + repository: str, + user: str + ) -> t.Union[str, list]: + """Retrieve issue(s) from a GitHub repository.""" links = [] - numbers = set(numbers) # Convert from list to set to remove duplicates, if any - if not numbers: - await ctx.invoke(self.bot.get_command('help'), 'issue') - return + return "Numbers not found." if len(numbers) > MAX_REQUESTS: - embed = discord.Embed( - title=random.choice(ERROR_REPLIES), - color=Colours.soft_red, - description=f"Too many issues/PRs! (maximum of {MAX_REQUESTS})" - ) - await ctx.send(embed=embed) - return + return "Max requests hit." for number in numbers: url = f"https://api.github.com/repos/{user}/{repository}/issues/{number}" @@ -63,7 +51,7 @@ class Issues(commands.Cog): if r.status in BAD_RESPONSE: log.warning(f"Received response {r.status} from: {url}") - return await ctx.send(f"[{str(r.status)}] #{number} {BAD_RESPONSE.get(r.status)}") + return f"[{str(r.status)}] #{number} {BAD_RESPONSE.get(r.status)}" # The initial API request is made to the issues API endpoint, which will return information # if the issue or PR is present. However, the scope of information returned for PRs differs @@ -92,15 +80,69 @@ class Issues(commands.Cog): issue_url = json_data.get("html_url") links.append([icon_url, f"[{repository}] #{number} {json_data.get('title')}", issue_url]) - # Issue/PR format: emoji to show if open/closed/merged, number and the title as a singular link. - description_list = ["{0} [{1}]({2})".format(*link) for link in links] + return links + + @staticmethod + def get_embed(result: list, user: str = "python-discord", repository: str = "") -> discord.Embed: + """Get Response Embed.""" + description_list = ["{0} [{1}]({2})".format(*link) for link in result] resp = discord.Embed( colour=Colours.bright_green, description='\n'.join(description_list) ) resp.set_author(name="GitHub", url=f"https://github.com/{user}/{repository}") - await ctx.send(embed=resp) + return resp + + @commands.command(aliases=("pr",)) + @override_in_channel(WHITELISTED_CHANNELS + (Channels.dev_contrib, Channels.dev_branding)) + async def issue( + self, + ctx: commands.Context, + numbers: commands.Greedy[int], + repository: str = "sir-lancebot", + user: str = "python-discord" + ) -> None: + """Command to retrieve issue(s) from a GitHub repository.""" + print(numbers) + result = await self.fetch_issues(set(numbers), repository, user) + + if result == "Numbers not found.": + await ctx.invoke(self.bot.get_command('help'), 'issue') + + elif result == "Max requests hit.": + embed = discord.Embed( + title=random.choice(ERROR_REPLIES), + color=Colours.soft_red, + description=f"Too many issues/PRs! (maximum of {MAX_REQUESTS})" + ) + await ctx.send(embed=embed) + + elif isinstance(result, list): + # Issue/PR format: emoji to show if open/closed/merged, number and the title as a singular link. + resp = self.get_embed(result, user, repository) + await ctx.send(embed=resp) + + elif isinstance(result, str): + await ctx.send(result) + + @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 #.""" + message_repo_issue_map = re.findall(r".+?(bot|meta|sir-lancebot|logcord)#(\d+)", message.content) + links = [] + + if message_repo_issue_map: + for repo_issue in message_repo_issue_map: + result = await self.fetch_issues({repo_issue[1]}, repo_issue[0], "python-discord") + if isinstance(result, list): + links.append(*result) + + if not links: + return + + resp = self.get_embed(links, "python-discord") + await message.channel.send(embed=resp) def setup(bot: commands.Bot) -> None: -- cgit v1.2.3 From ee829251a1f83b8620a76e6c81fe907ada1e1cc1 Mon Sep 17 00:00:00 2001 From: Xithrius <15021300+Xithrius@users.noreply.github.com> Date: Sun, 24 Jan 2021 01:21:24 -0800 Subject: Put a space after the colons for #562 trivia. --- bot/resources/evergreen/trivia_quiz.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'bot') diff --git a/bot/resources/evergreen/trivia_quiz.json b/bot/resources/evergreen/trivia_quiz.json index a5e3a3e4..faa3bc3b 100644 --- a/bot/resources/evergreen/trivia_quiz.json +++ b/bot/resources/evergreen/trivia_quiz.json @@ -250,15 +250,15 @@ }, { "id": 136, - "question":"The United Nations headquarters is located at which city?", - "answer":"New York", - "info":"The United Nations is headquartered in New York City in a complex designed by a board of architects led by Wallace Harrison and built by the architectural firm Harrison & Abramovitz. The complex has served as the official headquarters of the United Nations since its completion in 1951." + "question": "The United Nations headquarters is located at which city?", + "answer": "New York", + "info": "The United Nations is headquartered in New York City in a complex designed by a board of architects led by Wallace Harrison and built by the architectural firm Harrison & Abramovitz. The complex has served as the official headquarters of the United Nations since its completion in 1951." }, { "id": 137, - "question":"At what year did Christopher Columbus discover America?", - "answer":"1492", - "info":"The explorer Christopher Columbus made four trips across the Atlantic Ocean from Spain: in 1492, 1493, 1498 and 1502. He was determined to find a direct water route west from Europe to Asia, but he never did. Instead, he stumbled upon the Americas" + "question": "At what year did Christopher Columbus discover America?", + "answer": "1492", + "info": "The explorer Christopher Columbus made four trips across the Atlantic Ocean from Spain: in 1492, 1493, 1498 and 1502. He was determined to find a direct water route west from Europe to Asia, but he never did. Instead, he stumbled upon the Americas" } ] } -- cgit v1.2.3 From 948a64f3de06b946f7e4c3e1e730dd6849c58ca1 Mon Sep 17 00:00:00 2001 From: xithrius Date: Sun, 24 Jan 2021 03:00:47 -0800 Subject: Refactored the xkcd command, added a refresher. --- bot/exts/evergreen/xkcd.py | 113 ++++++++++++++++++++++----------------------- 1 file changed, 56 insertions(+), 57 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/xkcd.py b/bot/exts/evergreen/xkcd.py index 11477216..5c100bf0 100644 --- a/bot/exts/evergreen/xkcd.py +++ b/bot/exts/evergreen/xkcd.py @@ -1,72 +1,71 @@ import logging -import random +from random import randint +from typing import Dict, Optional, Union -import discord -from discord.ext import commands +from discord import Embed +from discord.ext import tasks +from discord.ext.commands import Cog, Context, command + +from bot.bot import Bot log = logging.getLogger(__name__) +URL = "https://xkcd.com/{0}/info.0.json" +LATEST = "https://xkcd.com/info.0.json" + -class XKCD(commands.Cog): - """A cog for posting the XKCD .""" +class XKCD(Cog): + """Retrieving XKCD comics.""" - def __init__(self, bot: commands.Bot): + def __init__(self, bot: Bot) -> None: self.bot = bot + self.latest_comic_info: Dict[str, Union[str, int]] = {} + self.get_latest_comic_info.start() - @commands.command(name="xkcd") - async def fetch_xkcd_comics(self, ctx: commands.Context, comic: str = "latest") -> None: - """Read your Fav XKCD comics.""" - if comic not in ["random", "latest"]: - url = f"https://xkcd.com/{comic}/info.0.json" - else: - url = "https://xkcd.com/info.0.json" - - # ---- random choice ----- - if comic == "random": - async with self.bot.http_session.get(url) as r: - json_data = await r.json() - random_pick = random.randint(1, int(json_data["num"])) - url = f"https://xkcd.com/{random_pick}/info.0.json" - - log.trace(f"Querying xkcd API: {url}") - async with self.bot.http_session.get(url) as r: - if r.status == "200": - json_data = await r.json() + def cog_unload(self) -> None: + """Cancels refreshing of the task for refreshing the most recent comic info.""" + self.get_latest_comic_info.cancel() + + @tasks.loop(minutes=30) + async def get_latest_comic_info(self) -> None: + """Refreshes latest comic's information ever 30 minutes. Also used for finding a random comic.""" + async with self.bot.http_session.get(LATEST) as resp: + if resp.status == 200: + self.latest_comic_info = await resp.json() else: - # ----- Exception handling | Guides to use ------ - log.warning(f"Received response {r.status} from: {url}") - # -- get the latest comic number --- - url = f"https://xkcd.com/info.0.json" - async with self.bot.http_session.get(url) as r: - latest_data = await r.json() - - # --- beautify response --- - latest_num = latest_data["num"] - resp = discord.Embed( - title="Guides | Usage", - description=f''' - .xkcd latest (Retrieves the latest comic) - .xkcd random (Retrieves random comic) - .xkcd number (Enter a comic number between 1 & {latest_num}) - ''' - ) - return await ctx.send(embed=resp) - - # --- response variables ---- - day, month, year = json_data["day"], json_data["month"], json_data["year"] - comic_number = json_data["num"] - - # ---- beautify response ---- - embed = discord.Embed( - title=json_data['title'], - description=json_data["alt"] - ) - embed.set_image(url=json_data['img']) - embed.set_footer(text=f"Post date : {day}-{month}-{year} | xkcd comics - {comic_number}") + log.debug(f"Failed to get latest XKCD comic information. Status code {resp.status}") + + @command(name="xkcd") + async def fetch_xkcd_comics(self, ctx: Context, comic: Optional[str]) -> None: + """ + Getting an xkcd comic's information along with the image. + + To get a random comic, don't type any number as an argument. To get the latest, enter 0. + """ + embed = Embed() + + comic = comic or randint(1, self.latest_comic_info['num']) + + if comic == "latest": + info = self.latest_comic_info + + else: + async with self.bot.http_session.get(URL.format(comic)) as resp: + if resp.status == 200: + info = await resp.json() + else: + embed.description = f"{resp.status}: Could not retrieve xkcd comic #{comic}." + log.debug(f"Retrieving xkcd comic #{comic} failed with status code {resp.status}.") + await ctx.send(embed=embed) + return + + embed.set_image(url=info["img"]) + date = f"{info['year']}/{info['month']}/{info['day']}" + embed.set_footer(text=f"{date} - #{comic}, \'{info['safe_title']}\'") await ctx.send(embed=embed) -def setup(bot: commands.Bot) -> None: - """XKCD Cog load.""" +def setup(bot: Bot) -> None: + """Loading the XKCD cog.""" bot.add_cog(XKCD(bot)) -- cgit v1.2.3 From 075559cddd1ca3d99c5d85e4bc4f01687d845fda Mon Sep 17 00:00:00 2001 From: xithrius Date: Sun, 24 Jan 2021 03:17:40 -0800 Subject: Added footer comic number for random and latest. --- bot/exts/evergreen/xkcd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/xkcd.py b/bot/exts/evergreen/xkcd.py index 5c100bf0..06c3b4a2 100644 --- a/bot/exts/evergreen/xkcd.py +++ b/bot/exts/evergreen/xkcd.py @@ -61,7 +61,7 @@ class XKCD(Cog): embed.set_image(url=info["img"]) date = f"{info['year']}/{info['month']}/{info['day']}" - embed.set_footer(text=f"{date} - #{comic}, \'{info['safe_title']}\'") + embed.set_footer(text=f"{date} - #{info['num']}, \'{info['safe_title']}\'") await ctx.send(embed=embed) -- cgit v1.2.3 From 2d52b09977b73b5f7583e914ffc5465321548f6a Mon Sep 17 00:00:00 2001 From: xithrius Date: Sun, 24 Jan 2021 03:23:34 -0800 Subject: Added soft red color if the command fails. --- bot/exts/evergreen/xkcd.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'bot') diff --git a/bot/exts/evergreen/xkcd.py b/bot/exts/evergreen/xkcd.py index 06c3b4a2..b2f8879a 100644 --- a/bot/exts/evergreen/xkcd.py +++ b/bot/exts/evergreen/xkcd.py @@ -7,6 +7,7 @@ from discord.ext import tasks from discord.ext.commands import Cog, Context, command from bot.bot import Bot +from bot.constants import Colours log = logging.getLogger(__name__) @@ -55,6 +56,7 @@ class XKCD(Cog): info = await resp.json() else: embed.description = f"{resp.status}: Could not retrieve xkcd comic #{comic}." + embed.colour = Colours.soft_red log.debug(f"Retrieving xkcd comic #{comic} failed with status code {resp.status}.") await ctx.send(embed=embed) return -- cgit v1.2.3 From f701e93cfb768f7a04c786437cdbe3a7105d4bc9 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Sun, 24 Jan 2021 16:58:07 +0530 Subject: Send a message on draw (was catching a error earlier) ; Improve send game over (winner/loser) code ; add case_insensitive alias --- bot/exts/evergreen/connect_four.py | 57 ++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 27 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/connect_four.py b/bot/exts/evergreen/connect_four.py index be370a83..7c5261c5 100644 --- a/bot/exts/evergreen/connect_four.py +++ b/bot/exts/evergreen/connect_four.py @@ -71,7 +71,7 @@ class Game: """Formats and outputs the Connect Four grid to the channel.""" title = ( f'Connect 4: {self.player1.display_name}' - f'VS {self.bot.user.display_name if isinstance(self.player2, AI) else self.player2.display_name}' + f' VS {self.bot.user.display_name if isinstance(self.player2, AI) else self.player2.display_name}' ) rows = [" ".join(EMOJIS[s] for s in row) for row in self.grid] @@ -88,14 +88,23 @@ class Game: await self.message.add_reaction(CROSS_EMOJI) await self.message.edit(content=None, embed=embed) + async def game_over(self, winner: discord.user, loser: discord.user) -> None: + """Removes games from list of current games and announces to public chat.""" + await self.channel.send(f"Game Over! {winner.mention} won against {loser.mention}") + await self.print_grid() + async def start_game(self) -> None: """Begins the game.""" self.player_active, self.player_inactive = self.player1, self.player2 while True: await self.print_grid() + if isinstance(self.player_active, AI): coords = self.player_active.play() + if not coords: + await self.channel.send(f"Game Over! Its's A Draw :tada:") + await self.print_grid() else: coords = await self.player_turn() @@ -103,18 +112,10 @@ class Game: return if self.check_win(coords, 1 if self.player_active == self.player1 else 2): - if isinstance(self.player_active, AI): - await self.channel.send(f"Game Over! {self.player_inactive.mention} lost against" - f" {self.bot.user.mention}") - else: - if isinstance(self.player_inactive, AI): - await self.channel.send(f"Game Over! {self.player_active.mention} won against" - f" {self.bot.user.mention}") - else: - await self.channel.send( - f"Game Over! {self.player_active.mention} won against {self.player_inactive.mention}" - ) - await self.print_grid() + await self.game_over( + self.bot.user if isinstance(self.player_active, AI) else {self.player_active}, + self.bot.user if isinstance(self.player_inactive, AI) else {self.player_inactive}, + ) return self.player_active, self.player_inactive = self.player_inactive, self.player_active @@ -122,9 +123,9 @@ class Game: def predicate(self, reaction: discord.Reaction, user: discord.Member) -> bool: """The predicate to check for the player's reaction.""" return ( - reaction.message.id == self.message.id - and user.id == self.player_active.id - and str(reaction.emoji) in (*self.unicode_numbers, CROSS_EMOJI) + reaction.message.id == self.message.id + and user.id == self.player_active.id + and str(reaction.emoji) in (*self.unicode_numbers, CROSS_EMOJI) ) async def player_turn(self) -> Coordinate: @@ -142,9 +143,7 @@ class Game: else: if str(reaction.emoji) == CROSS_EMOJI: await message.delete() - await self.channel.send( - f"{user.mention} has abandoned the game :(" - ) + await self.channel.send(f"{self.player_active.user} surrendered. Game over!") return await message.delete() @@ -235,7 +234,7 @@ class AI: """Picks a random coordinate from the possible ones.""" return random.choice(coord_list) - def play(self) -> Coordinate: + def play(self) -> typing.Union[Coordinate, bool]: """ Plays for the AI. @@ -247,10 +246,13 @@ class AI: """ possible_coords = self.get_possible_places() + if not possible_coords: + return False + coords = ( - self.check_ai_win(possible_coords) - or self.check_player_win(possible_coords) - or self.random_coords(possible_coords) + self.check_ai_win(possible_coords) + or self.check_player_win(possible_coords) + or self.random_coords(possible_coords) ) row, column = coords @@ -354,14 +356,15 @@ class ConnectFour(commands.Cog): @commands.group( invoke_without_command=True, - aliases=["4inarow", "connect4", "connectfour", "c4"] + aliases=["4inarow", "connect4", "connectfour", "c4"], + case_insensitive=True ) async def connect_four( self, ctx: commands.Context, board_size: int = 7, - emoji1: EMOJI_CHECK = ":blue_circle:", - emoji2: EMOJI_CHECK = ":red_circle:" + emoji1: EMOJI_CHECK = "\U0001f535", + emoji2: EMOJI_CHECK = "\U0001f534" ) -> None: """ Play the classic game of Connect Four with someone! @@ -421,7 +424,7 @@ class ConnectFour(commands.Cog): self, ctx: commands.Context, board_size: int = 7, - emoji1: EMOJI_CHECK = ":blue_circle:" + emoji1: EMOJI_CHECK = "\U0001f535" ) -> None: """Play Connect Four against a computer player.""" if isinstance(emoji1, str) and len(emoji1) > 1: -- cgit v1.2.3 From 914f2a8340c8c5636589f4e11de880f48cac52e2 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Sun, 24 Jan 2021 17:02:11 +0530 Subject: Fix lint issues --- bot/exts/evergreen/connect_four.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/connect_four.py b/bot/exts/evergreen/connect_four.py index 7c5261c5..51d1adc3 100644 --- a/bot/exts/evergreen/connect_four.py +++ b/bot/exts/evergreen/connect_four.py @@ -103,7 +103,7 @@ class Game: if isinstance(self.player_active, AI): coords = self.player_active.play() if not coords: - await self.channel.send(f"Game Over! Its's A Draw :tada:") + await self.channel.send("Game Over! It's A Draw :tada:") await self.print_grid() else: coords = await self.player_turn() @@ -123,9 +123,9 @@ class Game: def predicate(self, reaction: discord.Reaction, user: discord.Member) -> bool: """The predicate to check for the player's reaction.""" return ( - reaction.message.id == self.message.id - and user.id == self.player_active.id - and str(reaction.emoji) in (*self.unicode_numbers, CROSS_EMOJI) + reaction.message.id == self.message.id + and user.id == self.player_active.id + and str(reaction.emoji) in (*self.unicode_numbers, CROSS_EMOJI) ) async def player_turn(self) -> Coordinate: @@ -250,9 +250,9 @@ class AI: return False coords = ( - self.check_ai_win(possible_coords) - or self.check_player_win(possible_coords) - or self.random_coords(possible_coords) + self.check_ai_win(possible_coords) + or self.check_player_win(possible_coords) + or self.random_coords(possible_coords) ) row, column = coords -- cgit v1.2.3 From 295f0d33a4257d7d930a4da5ddf2f845f86ac730 Mon Sep 17 00:00:00 2001 From: xithrius Date: Sun, 24 Jan 2021 03:59:09 -0800 Subject: Added handling for comic arguments and interactive comics. --- bot/exts/evergreen/xkcd.py | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/xkcd.py b/bot/exts/evergreen/xkcd.py index b2f8879a..cb61e5b8 100644 --- a/bot/exts/evergreen/xkcd.py +++ b/bot/exts/evergreen/xkcd.py @@ -1,4 +1,5 @@ import logging +import re from random import randint from typing import Dict, Optional, Union @@ -11,8 +12,8 @@ from bot.constants import Colours log = logging.getLogger(__name__) -URL = "https://xkcd.com/{0}/info.0.json" -LATEST = "https://xkcd.com/info.0.json" +COMIC_FORMAT = re.compile(r"latest|[0-9]+") +BASE_URL = "https://xkcd.com" class XKCD(Cog): @@ -30,7 +31,7 @@ class XKCD(Cog): @tasks.loop(minutes=30) async def get_latest_comic_info(self) -> None: """Refreshes latest comic's information ever 30 minutes. Also used for finding a random comic.""" - async with self.bot.http_session.get(LATEST) as resp: + async with self.bot.http_session.get(f"{BASE_URL}/info.0.json") as resp: if resp.status == 200: self.latest_comic_info = await resp.json() else: @@ -41,29 +42,42 @@ class XKCD(Cog): """ Getting an xkcd comic's information along with the image. - To get a random comic, don't type any number as an argument. To get the latest, enter 0. + To get a random comic, don't type any number as an argument. To get the latest, type 'latest'. """ - embed = Embed() + embed = Embed(title=f"XKCD comic #{self.latest_comic_info['num'] if comic == 'latest' else comic}") - comic = comic or randint(1, self.latest_comic_info['num']) + embed.colour = Colours.soft_red + + if (comic := re.match(COMIC_FORMAT, comic)) is None: + embed.description = "Inputted comic parameter should either be an integer or 'latest'." + await ctx.send(embed=embed) + return + + comic = comic.group(0) or randint(1, self.latest_comic_info['num']) if comic == "latest": info = self.latest_comic_info else: - async with self.bot.http_session.get(URL.format(comic)) as resp: + async with self.bot.http_session.get(f"{BASE_URL}/{comic}/info.0.json") as resp: if resp.status == 200: info = await resp.json() else: embed.description = f"{resp.status}: Could not retrieve xkcd comic #{comic}." - embed.colour = Colours.soft_red log.debug(f"Retrieving xkcd comic #{comic} failed with status code {resp.status}.") await ctx.send(embed=embed) return - embed.set_image(url=info["img"]) - date = f"{info['year']}/{info['month']}/{info['day']}" - embed.set_footer(text=f"{date} - #{info['num']}, \'{info['safe_title']}\'") + if info["img"][:-3] in ("jpg", "png", "gif"): + embed.set_image(url=info["img"]) + date = f"{info['year']}/{info['month']}/{info['day']}" + embed.set_footer(text=f"{date} - #{info['num']}, \'{info['safe_title']}\'") + embed.colour = Colours.soft_green + else: + embed.description = ( + "Selected comic is interactive, and cannot be displayed within an embed.\n" + f"Comic can be viewed [here](https://xkcd.com/{info['num']})" + ) await ctx.send(embed=embed) -- cgit v1.2.3 From f5ea1ff1a9013df7426abc3076f66d12e64cb6b8 Mon Sep 17 00:00:00 2001 From: xithrius Date: Sun, 24 Jan 2021 04:00:38 -0800 Subject: Grammer formatting. --- bot/exts/evergreen/xkcd.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/xkcd.py b/bot/exts/evergreen/xkcd.py index cb61e5b8..91006715 100644 --- a/bot/exts/evergreen/xkcd.py +++ b/bot/exts/evergreen/xkcd.py @@ -75,8 +75,8 @@ class XKCD(Cog): embed.colour = Colours.soft_green else: embed.description = ( - "Selected comic is interactive, and cannot be displayed within an embed.\n" - f"Comic can be viewed [here](https://xkcd.com/{info['num']})" + "The selected comic is interactive, and cannot be displayed within an embed.\n" + f"Comic can be viewed [here](https://xkcd.com/{info['num']})." ) await ctx.send(embed=embed) -- cgit v1.2.3 From 2c14deb0cd25ca8f1c80fc6e02d321dca1af75d1 Mon Sep 17 00:00:00 2001 From: xithrius Date: Sun, 24 Jan 2021 04:24:09 -0800 Subject: Finished up optimization of statements. --- bot/exts/evergreen/xkcd.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/xkcd.py b/bot/exts/evergreen/xkcd.py index 91006715..e387d3c8 100644 --- a/bot/exts/evergreen/xkcd.py +++ b/bot/exts/evergreen/xkcd.py @@ -44,16 +44,16 @@ class XKCD(Cog): To get a random comic, don't type any number as an argument. To get the latest, type 'latest'. """ - embed = Embed(title=f"XKCD comic #{self.latest_comic_info['num'] if comic == 'latest' else comic}") + embed = Embed(title=f"XKCD comic '{comic}'") embed.colour = Colours.soft_red - if (comic := re.match(COMIC_FORMAT, comic)) is None: + if comic and (comic := re.match(COMIC_FORMAT, comic)) is None: embed.description = "Inputted comic parameter should either be an integer or 'latest'." await ctx.send(embed=embed) return - comic = comic.group(0) or randint(1, self.latest_comic_info['num']) + comic = randint(1, self.latest_comic_info['num']) if comic is None else comic.group(0) if comic == "latest": info = self.latest_comic_info @@ -63,12 +63,15 @@ class XKCD(Cog): if resp.status == 200: info = await resp.json() else: + embed.title = f"XKCD comic #{comic}" embed.description = f"{resp.status}: Could not retrieve xkcd comic #{comic}." log.debug(f"Retrieving xkcd comic #{comic} failed with status code {resp.status}.") await ctx.send(embed=embed) return - if info["img"][:-3] in ("jpg", "png", "gif"): + embed.title = f"XKCD comic #{info['num']}" + + if info["img"][-3:] in ("jpg", "png", "gif"): embed.set_image(url=info["img"]) date = f"{info['year']}/{info['month']}/{info['day']}" embed.set_footer(text=f"{date} - #{info['num']}, \'{info['safe_title']}\'") -- cgit v1.2.3 From 62b1b277146c19ba441b5dcceec073489dd7178a Mon Sep 17 00:00:00 2001 From: Xithrius <15021300+Xithrius@users.noreply.github.com> Date: Sun, 24 Jan 2021 04:38:59 -0800 Subject: Changed comic argument error for fluency of reading. Co-authored-by: ChrisJL --- bot/exts/evergreen/xkcd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/xkcd.py b/bot/exts/evergreen/xkcd.py index e387d3c8..674ad4b0 100644 --- a/bot/exts/evergreen/xkcd.py +++ b/bot/exts/evergreen/xkcd.py @@ -49,7 +49,7 @@ class XKCD(Cog): embed.colour = Colours.soft_red if comic and (comic := re.match(COMIC_FORMAT, comic)) is None: - embed.description = "Inputted comic parameter should either be an integer or 'latest'." + embed.description = "Comic parameter should either be an integer or 'latest'." await ctx.send(embed=embed) return -- cgit v1.2.3 From a81d30f34dc4d4fa6e8550437e6d329a4da4e746 Mon Sep 17 00:00:00 2001 From: xithrius Date: Sun, 24 Jan 2021 05:41:58 -0800 Subject: Removed newline between if/else statement. --- bot/exts/evergreen/xkcd.py | 1 - 1 file changed, 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/xkcd.py b/bot/exts/evergreen/xkcd.py index 674ad4b0..d3224bfe 100644 --- a/bot/exts/evergreen/xkcd.py +++ b/bot/exts/evergreen/xkcd.py @@ -57,7 +57,6 @@ class XKCD(Cog): if comic == "latest": info = self.latest_comic_info - else: async with self.bot.http_session.get(f"{BASE_URL}/{comic}/info.0.json") as resp: if resp.status == 200: -- cgit v1.2.3 From 53af90f92258905c2bfc4c2db2341dfd1fdc0124 Mon Sep 17 00:00:00 2001 From: xithrius Date: Sun, 24 Jan 2021 06:52:15 -0800 Subject: Fixed linting errors. --- bot/bot.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'bot') diff --git a/bot/bot.py b/bot/bot.py index 112c9a48..81d59706 100644 --- a/bot/bot.py +++ b/bot/bot.py @@ -37,7 +37,6 @@ class Bot(commands.Bot): self.loop.create_task(self.check_channels()) self.loop.create_task(self.send_log(self.name, "Connected!")) - @property def member(self) -> Optional[discord.Member]: """Retrieves the guild member object for the bot.""" @@ -76,7 +75,7 @@ class Bot(commands.Bot): """Verifies that all channel constants refer to channels which exist.""" await self.wait_until_guild_available() all_channels = set(self.get_all_channels()) - for name, channel_id in vars(Channels).items(): + for name, channel_id in vars(constants.Channels).items(): if name.startswith('_'): continue if channel_id not in all_channels: -- cgit v1.2.3 From 7cdf800368e4e287a8fd2bc3b539395ff6c73e41 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Sun, 24 Jan 2021 17:10:08 +0200 Subject: Decrease timeout from 120 sec to 30 sec --- bot/exts/evergreen/tic_tac_toe.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/tic_tac_toe.py b/bot/exts/evergreen/tic_tac_toe.py index 22fff102..e1190502 100644 --- a/bot/exts/evergreen/tic_tac_toe.py +++ b/bot/exts/evergreen/tic_tac_toe.py @@ -58,7 +58,7 @@ class Player: ) try: - react, _ = await self.ctx.bot.wait_for('reaction_add', timeout=120.0, check=check_for_move) + react, _ = await self.ctx.bot.wait_for('reaction_add', timeout=30.0, check=check_for_move) except asyncio.TimeoutError: return True, None else: -- cgit v1.2.3 From fbe073cb5e8dca831b4126c5b221844032870d26 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Tue, 26 Jan 2021 16:28:36 +0530 Subject: Add in codeblock check --- bot/exts/evergreen/issues.py | 48 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 8 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/issues.py b/bot/exts/evergreen/issues.py index b701346c..1924d822 100644 --- a/bot/exts/evergreen/issues.py +++ b/bot/exts/evergreen/issues.py @@ -4,7 +4,7 @@ import re import typing as t import discord -from discord.ext import commands +from discord.ext import commands, tasks from bot.constants import Channels, Colours, ERROR_REPLIES, Emojis, Tokens, WHITELISTED_CHANNELS from bot.utils.decorators import override_in_channel @@ -17,15 +17,43 @@ BAD_RESPONSE = { } MAX_REQUESTS = 10 REQUEST_HEADERS = dict() +PYDIS_REPOS = "https://api.github.com/orgs/python-discord/repos" + if GITHUB_TOKEN := Tokens.github: REQUEST_HEADERS["Authorization"] = f"token {GITHUB_TOKEN}" - class Issues(commands.Cog): """Cog that allows users to retrieve issues from GitHub.""" def __init__(self, bot: commands.Bot): self.bot = bot + self.repos = [] + self.get_pydis_repos.start() + + @tasks.loop(minutes=30) + async def get_pydis_repos(self) -> None: + async with self.bot.http_session.get(PYDIS_REPOS) as resp: + if resp.status == 200: + data = await resp.json() + for repo in data: + self.repos.append(repo["full_name"].split("/")[1]) + else: + log.debug(f"Failed to get latest Pydis repositories. Status code {resp.status}") + + @staticmethod + def check_in_block(message: discord.Message, repo_issue: str) -> bool: + block = ( + re.findall(r"```([\s\S]*)?```", message.content) + or re.findall(r"```*\n([\s\S]*)?\n```", message.content) + or re.findall(r"```*([\s\S]*)?\n```", message.content) + or re.findall(r"```*\n([\s\S]*)?```", message.content) + or re.findall(r"`([\s\S]*)?`", message.content) + ) + print(block) + + if "#".join(repo_issue.split(" ")) in "".join([*block]): + return True + return False async def fetch_issues( self, @@ -44,7 +72,7 @@ class Issues(commands.Cog): for number in numbers: url = f"https://api.github.com/repos/{user}/{repository}/issues/{number}" merge_url = f"https://api.github.com/repos/{user}/{repository}/pulls/{number}/merge" - + print(url) log.trace(f"Querying GH issues API: {url}") async with self.bot.http_session.get(url, headers=REQUEST_HEADERS) as r: json_data = await r.json() @@ -104,7 +132,6 @@ class Issues(commands.Cog): user: str = "python-discord" ) -> None: """Command to retrieve issue(s) from a GitHub repository.""" - print(numbers) result = await self.fetch_issues(set(numbers), repository, user) if result == "Numbers not found.": @@ -129,14 +156,19 @@ 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 #.""" - message_repo_issue_map = re.findall(r".+?(bot|meta|sir-lancebot|logcord)#(\d+)", message.content) + repo_regex = "|".join(repo for repo in self.repos) + message_repo_issue_map = re.findall(fr".+?({repo_regex})#(\d+)", message.content) links = [] if message_repo_issue_map: for repo_issue in message_repo_issue_map: - result = await self.fetch_issues({repo_issue[1]}, repo_issue[0], "python-discord") - if isinstance(result, list): - links.append(*result) + if self.check_in_block(message, " ".join([*repo_issue])): + print("in") + continue + else: + result = await self.fetch_issues({repo_issue[1]}, repo_issue[0], "python-discord") + if isinstance(result, list): + links.append(*result) if not links: return -- cgit v1.2.3 From 2dcdec0defb0f75478cd344cabd431d02b506741 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Tue, 26 Jan 2021 16:36:24 +0530 Subject: Remove debug code and add docstrings. --- bot/exts/evergreen/issues.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/issues.py b/bot/exts/evergreen/issues.py index 1924d822..ba8a70cf 100644 --- a/bot/exts/evergreen/issues.py +++ b/bot/exts/evergreen/issues.py @@ -22,6 +22,7 @@ PYDIS_REPOS = "https://api.github.com/orgs/python-discord/repos" if GITHUB_TOKEN := Tokens.github: REQUEST_HEADERS["Authorization"] = f"token {GITHUB_TOKEN}" + class Issues(commands.Cog): """Cog that allows users to retrieve issues from GitHub.""" @@ -32,6 +33,7 @@ class Issues(commands.Cog): @tasks.loop(minutes=30) async def get_pydis_repos(self) -> None: + """Get all python-discord repositories on github.""" async with self.bot.http_session.get(PYDIS_REPOS) as resp: if resp.status == 200: data = await resp.json() @@ -42,6 +44,7 @@ class Issues(commands.Cog): @staticmethod def check_in_block(message: discord.Message, repo_issue: str) -> bool: + """Check whether the # is in codeblocks.""" block = ( re.findall(r"```([\s\S]*)?```", message.content) or re.findall(r"```*\n([\s\S]*)?\n```", message.content) @@ -49,7 +52,6 @@ class Issues(commands.Cog): or re.findall(r"```*\n([\s\S]*)?```", message.content) or re.findall(r"`([\s\S]*)?`", message.content) ) - print(block) if "#".join(repo_issue.split(" ")) in "".join([*block]): return True @@ -163,7 +165,6 @@ class Issues(commands.Cog): if message_repo_issue_map: for repo_issue in message_repo_issue_map: if self.check_in_block(message, " ".join([*repo_issue])): - print("in") continue else: result = await self.fetch_issues({repo_issue[1]}, repo_issue[0], "python-discord") -- cgit v1.2.3 From d80308f509489bfe6120020758721093af2df7f9 Mon Sep 17 00:00:00 2001 From: Shivansh-007 <69356296+Shivansh-007@users.noreply.github.com> Date: Tue, 26 Jan 2021 16:39:02 +0530 Subject: Remove debug code. Co-authored-by: Xithrius <15021300+Xithrius@users.noreply.github.com> --- bot/exts/evergreen/issues.py | 1 - 1 file changed, 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/issues.py b/bot/exts/evergreen/issues.py index ba8a70cf..946da354 100644 --- a/bot/exts/evergreen/issues.py +++ b/bot/exts/evergreen/issues.py @@ -74,7 +74,6 @@ class Issues(commands.Cog): for number in numbers: url = f"https://api.github.com/repos/{user}/{repository}/issues/{number}" merge_url = f"https://api.github.com/repos/{user}/{repository}/pulls/{number}/merge" - print(url) log.trace(f"Querying GH issues API: {url}") async with self.bot.http_session.get(url, headers=REQUEST_HEADERS) as r: json_data = await r.json() -- cgit v1.2.3 From ec45aac56861f3b7b8813957bf7e0e3a890fc44a Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Tue, 26 Jan 2021 16:54:30 +0530 Subject: Cache repo regex --- bot/exts/evergreen/issues.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/issues.py b/bot/exts/evergreen/issues.py index ba8a70cf..55bc8cf0 100644 --- a/bot/exts/evergreen/issues.py +++ b/bot/exts/evergreen/issues.py @@ -39,6 +39,7 @@ class Issues(commands.Cog): data = await resp.json() for repo in data: self.repos.append(repo["full_name"].split("/")[1]) + self.repo_regex = "|".join(repo for repo in self.repos) else: log.debug(f"Failed to get latest Pydis repositories. Status code {resp.status}") @@ -158,8 +159,7 @@ 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_regex = "|".join(repo for repo in self.repos) - message_repo_issue_map = re.findall(fr".+?({repo_regex})#(\d+)", message.content) + message_repo_issue_map = re.findall(fr".+?({self.repo_regex})#(\d+)", message.content) links = [] if message_repo_issue_map: -- cgit v1.2.3 From 65e5558df35892c2136f9182d07307b496582019 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Tue, 26 Jan 2021 16:56:18 +0530 Subject: Use list.extend while appending issue links --- bot/exts/evergreen/issues.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/issues.py b/bot/exts/evergreen/issues.py index 55bc8cf0..724be737 100644 --- a/bot/exts/evergreen/issues.py +++ b/bot/exts/evergreen/issues.py @@ -169,7 +169,7 @@ class Issues(commands.Cog): else: result = await self.fetch_issues({repo_issue[1]}, repo_issue[0], "python-discord") if isinstance(result, list): - links.append(*result) + links.extend(result) if not links: return -- cgit v1.2.3 From d973c1266b93a5baeb32a2f04ed797b8d0f0cd1b Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Tue, 26 Jan 2021 17:07:48 +0530 Subject: Change PYDIS_REPOS to PYTHON_DISCORD_REPOS --- bot/exts/evergreen/issues.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/issues.py b/bot/exts/evergreen/issues.py index 724be737..95187551 100644 --- a/bot/exts/evergreen/issues.py +++ b/bot/exts/evergreen/issues.py @@ -17,7 +17,7 @@ BAD_RESPONSE = { } MAX_REQUESTS = 10 REQUEST_HEADERS = dict() -PYDIS_REPOS = "https://api.github.com/orgs/python-discord/repos" +PYTHON_DISCORD_REPOS = "https://api.github.com/orgs/python-discord/repos" if GITHUB_TOKEN := Tokens.github: REQUEST_HEADERS["Authorization"] = f"token {GITHUB_TOKEN}" @@ -34,7 +34,7 @@ class Issues(commands.Cog): @tasks.loop(minutes=30) async def get_pydis_repos(self) -> None: """Get all python-discord repositories on github.""" - async with self.bot.http_session.get(PYDIS_REPOS) as resp: + async with self.bot.http_session.get(PYTHON_DISCORD_REPOS) as resp: if resp.status == 200: data = await resp.json() for repo in data: @@ -155,8 +155,9 @@ class Issues(commands.Cog): elif isinstance(result, str): await ctx.send(result) - + @commands.Cog.listener() + @override_in_channel(WHITELISTED_CHANNELS + (Channels.dev_contrib, Channels.dev_branding)) async def on_message(self, message: discord.Message) -> None: """Command to retrieve issue(s) from a GitHub repository using automatic linking if matching #.""" message_repo_issue_map = re.findall(fr".+?({self.repo_regex})#(\d+)", message.content) -- cgit v1.2.3 From 24f915bbe94452f80c7ab57b90b0f48d09e07e63 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Tue, 26 Jan 2021 17:13:12 +0530 Subject: Make the python_discord_repos' orgranisation name configurable --- bot/exts/evergreen/issues.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/issues.py b/bot/exts/evergreen/issues.py index 95187551..d816770c 100644 --- a/bot/exts/evergreen/issues.py +++ b/bot/exts/evergreen/issues.py @@ -17,7 +17,7 @@ BAD_RESPONSE = { } MAX_REQUESTS = 10 REQUEST_HEADERS = dict() -PYTHON_DISCORD_REPOS = "https://api.github.com/orgs/python-discord/repos" +PYTHON_DISCORD_REPOS = "https://api.github.com/orgs/{repo}/repos" if GITHUB_TOKEN := Tokens.github: REQUEST_HEADERS["Authorization"] = f"token {GITHUB_TOKEN}" @@ -34,7 +34,7 @@ class Issues(commands.Cog): @tasks.loop(minutes=30) async def get_pydis_repos(self) -> None: """Get all python-discord repositories on github.""" - async with self.bot.http_session.get(PYTHON_DISCORD_REPOS) as resp: + async with self.bot.http_session.get(PYTHON_DISCORD_REPOS.format(repo="python-discord")) as resp: if resp.status == 200: data = await resp.json() for repo in data: @@ -155,7 +155,7 @@ class Issues(commands.Cog): elif isinstance(result, str): await ctx.send(result) - + @commands.Cog.listener() @override_in_channel(WHITELISTED_CHANNELS + (Channels.dev_contrib, Channels.dev_branding)) async def on_message(self, message: discord.Message) -> None: -- cgit v1.2.3 From b6cda1a14a2a2e69dac59de675cbea75638c3f64 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Tue, 26 Jan 2021 17:23:30 +0530 Subject: Use enums for fetch issue errors. --- bot/exts/evergreen/issues.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/issues.py b/bot/exts/evergreen/issues.py index d816770c..bd62fc22 100644 --- a/bot/exts/evergreen/issues.py +++ b/bot/exts/evergreen/issues.py @@ -2,6 +2,7 @@ import logging import random import re import typing as t +from enum import Enum import discord from discord.ext import commands, tasks @@ -23,6 +24,12 @@ if GITHUB_TOKEN := Tokens.github: REQUEST_HEADERS["Authorization"] = f"token {GITHUB_TOKEN}" +class FetchIssueErrors(Enum): + value_error = "Numbers not found." + max_requests = "Max requests hit." + + + class Issues(commands.Cog): """Cog that allows users to retrieve issues from GitHub.""" @@ -67,10 +74,10 @@ class Issues(commands.Cog): """Retrieve issue(s) from a GitHub repository.""" links = [] if not numbers: - return "Numbers not found." + return FetchIssueErrors.value_error if len(numbers) > MAX_REQUESTS: - return "Max requests hit." + return FetchIssueErrors.max_requests for number in numbers: url = f"https://api.github.com/repos/{user}/{repository}/issues/{number}" @@ -137,10 +144,10 @@ class Issues(commands.Cog): """Command to retrieve issue(s) from a GitHub repository.""" result = await self.fetch_issues(set(numbers), repository, user) - if result == "Numbers not found.": + if result == FetchIssueErrors.value_error: await ctx.invoke(self.bot.get_command('help'), 'issue') - elif result == "Max requests hit.": + elif result == FetchIssueErrors.max_requests: embed = discord.Embed( title=random.choice(ERROR_REPLIES), color=Colours.soft_red, -- cgit v1.2.3 From 9d5352fcf1c4b9d09d9aba9632689f54beeb4087 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Tue, 26 Jan 2021 17:24:26 +0530 Subject: Fix lint issues --- bot/exts/evergreen/issues.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/issues.py b/bot/exts/evergreen/issues.py index bd62fc22..d258cc3c 100644 --- a/bot/exts/evergreen/issues.py +++ b/bot/exts/evergreen/issues.py @@ -2,7 +2,7 @@ import logging import random import re import typing as t -from enum import Enum +from enum import Enum import discord from discord.ext import commands, tasks -- cgit v1.2.3 From 8b71066b6dd645918cdceef389eb98d334c62434 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Tue, 26 Jan 2021 17:27:32 +0530 Subject: Add docstring to FetchIssueErrors and remove extra new line --- bot/exts/evergreen/issues.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/issues.py b/bot/exts/evergreen/issues.py index d6790edf..c9f87957 100644 --- a/bot/exts/evergreen/issues.py +++ b/bot/exts/evergreen/issues.py @@ -25,11 +25,12 @@ if GITHUB_TOKEN := Tokens.github: class FetchIssueErrors(Enum): + """Errors returned in fetch issues.""" + value_error = "Numbers not found." max_requests = "Max requests hit." - class Issues(commands.Cog): """Cog that allows users to retrieve issues from GitHub.""" -- cgit v1.2.3 From d2f9aa0d2236426e88334483959938328950f357 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Wed, 27 Jan 2021 10:09:05 +0530 Subject: Improve code block regex --- bot/exts/evergreen/issues.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/issues.py b/bot/exts/evergreen/issues.py index c9f87957..d2c70d4b 100644 --- a/bot/exts/evergreen/issues.py +++ b/bot/exts/evergreen/issues.py @@ -23,6 +23,12 @@ PYTHON_DISCORD_REPOS = "https://api.github.com/orgs/{repo}/repos" if GITHUB_TOKEN := Tokens.github: REQUEST_HEADERS["Authorization"] = f"token {GITHUB_TOKEN}" +CODE_BLOCK_RE = re.compile( + r"^`([^`\n]+)`" # Inline codeblock + r"|```(.+?)```", # Multiline codeblock + re.DOTALL | re.MULTILINE +) + class FetchIssueErrors(Enum): """Errors returned in fetch issues.""" @@ -54,15 +60,11 @@ class Issues(commands.Cog): @staticmethod def check_in_block(message: discord.Message, repo_issue: str) -> bool: """Check whether the # is in codeblocks.""" - block = ( - re.findall(r"```([\s\S]*)?```", message.content) - or re.findall(r"```*\n([\s\S]*)?\n```", message.content) - or re.findall(r"```*([\s\S]*)?\n```", message.content) - or re.findall(r"```*\n([\s\S]*)?```", message.content) - or re.findall(r"`([\s\S]*)?`", message.content) - ) + block = re.findall(CODE_BLOCK_RE, message.content) - if "#".join(repo_issue.split(" ")) in "".join([*block]): + if not block: + return False + elif "#".join(repo_issue.split(" ")) in "".join([*block[0]]): return True return False -- cgit v1.2.3 From a7ffa0926b47bf40cd034eeb2b5e9d5dcd04798f Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Wed, 27 Jan 2021 10:43:19 +0530 Subject: Add check for in category and in remove overide_channel check and do it without decorator --- bot/constants.py | 8 ++++++++ bot/exts/evergreen/issues.py | 19 ++++++++++++++----- 2 files changed, 22 insertions(+), 5 deletions(-) (limited to 'bot') diff --git a/bot/constants.py b/bot/constants.py index 1d41a53e..ce1ca29a 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -9,6 +9,7 @@ __all__ = ( "AdventOfCode", "Branding", "Channels", + "Categories", "Client", "Colours", "Emojis", @@ -100,6 +101,7 @@ class Channels(NamedTuple): big_brother_logs = 468507907357409333 bot = 267659945086812160 checkpoint_test = 422077681434099723 + organisation = 551789653284356126 devalerts = 460181980097675264 devlog = int(environ.get("CHANNEL_DEVLOG", 622895325144940554)) dev_contrib = 635950537262759947 @@ -128,6 +130,12 @@ class Channels(NamedTuple): voice_chat_1 = 799647045886541885 +class Categories(NamedTuple): + development = 411199786025484308 + devprojects = 787641585624940544 + media = 799054581991997460 + + class Client(NamedTuple): name = "Sir Lancebot" guild = int(environ.get("BOT_GUILD", 267624335836053506)) diff --git a/bot/exts/evergreen/issues.py b/bot/exts/evergreen/issues.py index d2c70d4b..4ab3df2c 100644 --- a/bot/exts/evergreen/issues.py +++ b/bot/exts/evergreen/issues.py @@ -7,8 +7,7 @@ from enum import Enum import discord from discord.ext import commands, tasks -from bot.constants import Channels, Colours, ERROR_REPLIES, Emojis, Tokens, WHITELISTED_CHANNELS -from bot.utils.decorators import override_in_channel +from bot.constants import Categories, Channels, Colours, ERROR_REPLIES, Emojis, Tokens, WHITELISTED_CHANNELS log = logging.getLogger(__name__) @@ -16,13 +15,19 @@ BAD_RESPONSE = { 404: "Issue/pull request not located! Please enter a valid number!", 403: "Rate limit has been hit! Please try again later!" } + MAX_REQUESTS = 10 REQUEST_HEADERS = dict() -PYTHON_DISCORD_REPOS = "https://api.github.com/orgs/{repo}/repos" +PYTHON_DISCORD_REPOS = "https://api.github.com/orgs/{repo}/repos" if GITHUB_TOKEN := Tokens.github: REQUEST_HEADERS["Authorization"] = f"token {GITHUB_TOKEN}" +WHITELISTED_CATEGORIES = ( + Categories.devprojects, Categories.media, Categories.development +) +WHITELISTED_CHANNELS += (Channels.organisation) + CODE_BLOCK_RE = re.compile( r"^`([^`\n]+)`" # Inline codeblock r"|```(.+?)```", # Multiline codeblock @@ -135,7 +140,6 @@ class Issues(commands.Cog): return resp @commands.command(aliases=("pr",)) - @override_in_channel(WHITELISTED_CHANNELS + (Channels.dev_contrib, Channels.dev_branding)) async def issue( self, ctx: commands.Context, @@ -144,6 +148,9 @@ class Issues(commands.Cog): user: str = "python-discord" ) -> None: """Command to retrieve issue(s) from a GitHub repository.""" + if ctx.channel.category not in WHITELISTED_CATEGORIES or ctx.channel.category in WHITELISTED_CHANNELS: + return + result = await self.fetch_issues(set(numbers), repository, user) if result == FetchIssueErrors.value_error: @@ -166,9 +173,11 @@ class Issues(commands.Cog): await ctx.send(result) @commands.Cog.listener() - @override_in_channel(WHITELISTED_CHANNELS + (Channels.dev_contrib, Channels.dev_branding)) async def on_message(self, message: discord.Message) -> None: """Command to retrieve issue(s) from a GitHub repository using automatic linking if matching #.""" + if message.channel.category not in WHITELISTED_CATEGORIES or message.channel.category in WHITELISTED_CHANNELS: + return + message_repo_issue_map = re.findall(fr".+?({self.repo_regex})#(\d+)", message.content) links = [] -- cgit v1.2.3 From 65260f66e6e7d3a9bff8b19c4a498643d2e664aa Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Wed, 27 Jan 2021 16:58:53 +0530 Subject: Fix return type annotations --- bot/exts/evergreen/issues.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/issues.py b/bot/exts/evergreen/issues.py index 4ab3df2c..8b02e874 100644 --- a/bot/exts/evergreen/issues.py +++ b/bot/exts/evergreen/issues.py @@ -26,7 +26,7 @@ if GITHUB_TOKEN := Tokens.github: WHITELISTED_CATEGORIES = ( Categories.devprojects, Categories.media, Categories.development ) -WHITELISTED_CHANNELS += (Channels.organisation) +WHITELISTED_CHANNELS += Channels.organisation CODE_BLOCK_RE = re.compile( r"^`([^`\n]+)`" # Inline codeblock @@ -78,7 +78,7 @@ class Issues(commands.Cog): numbers: set, repository: str, user: str - ) -> t.Union[str, list]: + ) -> t.Union[FetchIssueErrors, str, list]: """Retrieve issue(s) from a GitHub repository.""" links = [] if not numbers: -- cgit v1.2.3 From 661ab2cc966c96d6f05dfc0444f7569b2a8fd727 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Thu, 28 Jan 2021 04:44:36 +0530 Subject: Add http status dog and add http_cat to group http_status --- bot/exts/evergreen/status_cats.py | 33 -------------------- bot/exts/evergreen/status_codes.py | 63 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 33 deletions(-) delete mode 100644 bot/exts/evergreen/status_cats.py create mode 100644 bot/exts/evergreen/status_codes.py (limited to 'bot') diff --git a/bot/exts/evergreen/status_cats.py b/bot/exts/evergreen/status_cats.py deleted file mode 100644 index 586b8378..00000000 --- a/bot/exts/evergreen/status_cats.py +++ /dev/null @@ -1,33 +0,0 @@ -from http import HTTPStatus - -import discord -from discord.ext import commands - - -class StatusCats(commands.Cog): - """Commands that give HTTP statuses described and visualized by cats.""" - - def __init__(self, bot: commands.Bot): - self.bot = bot - - @commands.command(aliases=['statuscat']) - async def http_cat(self, ctx: commands.Context, code: int) -> None: - """Sends an embed with an image of a cat, potraying the status code.""" - embed = discord.Embed(title=f'**Status: {code}**') - - try: - HTTPStatus(code) - - except ValueError: - embed.set_footer(text='Inputted status code does not exist.') - - else: - embed.set_image(url=f'https://http.cat/{code}.jpg') - - finally: - await ctx.send(embed=embed) - - -def setup(bot: commands.Bot) -> None: - """Load the StatusCats cog.""" - bot.add_cog(StatusCats(bot)) diff --git a/bot/exts/evergreen/status_codes.py b/bot/exts/evergreen/status_codes.py new file mode 100644 index 00000000..eebc23af --- /dev/null +++ b/bot/exts/evergreen/status_codes.py @@ -0,0 +1,63 @@ +import re +from http import HTTPStatus + +import discord +from discord import HTTPException +from discord.ext import commands + + +class StatusCats(commands.Cog): + """Commands that give HTTP statuses described and visualized by cats and dogs.""" + + def __init__(self, bot: commands.Bot): + self.bot = bot + + @commands.group(name="http_status", aliases=("status", "httpstatus")) + async def http_status_group(self, ctx: commands.Context) -> None: + """Group containing dog and cat http status code commands.""" + if not ctx.invoked_subcommand: + await ctx.send_help(ctx.command) + + @http_status_group.command(aliases=['cat']) + async def http_cat(self, ctx: commands.Context, code: int) -> None: + """Sends an embed with an image of a cat, portraying the status code.""" + embed = discord.Embed(title=f'**Status: {code}**') + + try: + HTTPStatus(code) + + except ValueError: + embed.set_footer(text='Inputted status code does not exist.') + + else: + embed.set_image(url=f'https://http.cat/{code}.jpg') + + finally: + await ctx.send(embed=embed) + + @http_status_group.command(aliases=['dog']) + async def http_dog(self, ctx: commands.Context, code: int) -> None: + """Sends an embed with an image of a dog, portraying the status code.""" + embed = discord.Embed(title=f'**Status: {code}**') + + try: + HTTPStatus(code) + async with self.bot.http_session.get( + f'https://httpstatusdogs.com/img/{code}.jpg', + allow_redirects=False + ) as response: + if response.status != 302: + embed.set_image(url=f'https://httpstatusdogs.com/img/{code}.jpg') + else: + raise ValueError + + except ValueError: + embed.set_footer(text='Inputted status code does not exist.') + + finally: + await ctx.send(embed=embed) + + +def setup(bot: commands.Bot) -> None: + """Load the StatusCats cog.""" + bot.add_cog(StatusCats(bot)) -- cgit v1.2.3 From 0ae98d0d79c62cb71cc8287c0b391eef14f284ba Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Sat, 30 Jan 2021 06:50:31 +0530 Subject: Fix channel and category check logic --- bot/exts/evergreen/issues.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/issues.py b/bot/exts/evergreen/issues.py index 8b02e874..55ded054 100644 --- a/bot/exts/evergreen/issues.py +++ b/bot/exts/evergreen/issues.py @@ -26,7 +26,7 @@ if GITHUB_TOKEN := Tokens.github: WHITELISTED_CATEGORIES = ( Categories.devprojects, Categories.media, Categories.development ) -WHITELISTED_CHANNELS += Channels.organisation +WHITELISTED_CHANNELS_ON_MESSAGE = (Channels.organisation,) CODE_BLOCK_RE = re.compile( r"^`([^`\n]+)`" # Inline codeblock @@ -58,7 +58,7 @@ class Issues(commands.Cog): data = await resp.json() for repo in data: self.repos.append(repo["full_name"].split("/")[1]) - self.repo_regex = "|".join(repo for repo in self.repos) + self.repo_regex = "|".join(self.repos) else: log.debug(f"Failed to get latest Pydis repositories. Status code {resp.status}") @@ -148,7 +148,10 @@ class Issues(commands.Cog): user: str = "python-discord" ) -> None: """Command to retrieve issue(s) from a GitHub repository.""" - if ctx.channel.category not in WHITELISTED_CATEGORIES or ctx.channel.category in WHITELISTED_CHANNELS: + if not( + ctx.channel.category.id in WHITELISTED_CATEGORIES + or ctx.channel.id in WHITELISTED_CHANNELS + ): return result = await self.fetch_issues(set(numbers), repository, user) @@ -175,7 +178,10 @@ 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 #.""" - if message.channel.category not in WHITELISTED_CATEGORIES or message.channel.category in WHITELISTED_CHANNELS: + if not( + message.channel.category.id in WHITELISTED_CATEGORIES + or message.channel.id in WHITELISTED_CHANNELS_ON_MESSAGE + ): return message_repo_issue_map = re.findall(fr".+?({self.repo_regex})#(\d+)", message.content) @@ -183,9 +189,7 @@ class Issues(commands.Cog): if message_repo_issue_map: for repo_issue in message_repo_issue_map: - if self.check_in_block(message, " ".join([*repo_issue])): - continue - else: + if not self.check_in_block(message, " ".join([*repo_issue])): result = await self.fetch_issues({repo_issue[1]}, repo_issue[0], "python-discord") if isinstance(result, list): links.extend(result) -- cgit v1.2.3 From ac44307a4d4c7aabfafee0af89630a0f748fee00 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Sat, 30 Jan 2021 17:19:22 +0530 Subject: Fix PYTHON_DISCORD_REPOS format variable name and give it a better name --- bot/exts/evergreen/issues.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/issues.py b/bot/exts/evergreen/issues.py index 55ded054..72d88d04 100644 --- a/bot/exts/evergreen/issues.py +++ b/bot/exts/evergreen/issues.py @@ -19,7 +19,7 @@ BAD_RESPONSE = { MAX_REQUESTS = 10 REQUEST_HEADERS = dict() -PYTHON_DISCORD_REPOS = "https://api.github.com/orgs/{repo}/repos" +REPOS_API = "https://api.github.com/orgs/{org}/repos" if GITHUB_TOKEN := Tokens.github: REQUEST_HEADERS["Authorization"] = f"token {GITHUB_TOKEN}" @@ -53,7 +53,7 @@ class Issues(commands.Cog): @tasks.loop(minutes=30) async def get_pydis_repos(self) -> None: """Get all python-discord repositories on github.""" - async with self.bot.http_session.get(PYTHON_DISCORD_REPOS.format(repo="python-discord")) as resp: + async with self.bot.http_session.get(REPOS_API.format(org="python-discord")) as resp: if resp.status == 200: data = await resp.json() for repo in data: -- cgit v1.2.3 From a563d3ae23c1c1eff01a284e0510bdc364cc415a Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Sat, 30 Jan 2021 17:21:11 +0530 Subject: Fix misleading game_over docstring --- bot/exts/evergreen/connect_four.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/connect_four.py b/bot/exts/evergreen/connect_four.py index 51d1adc3..19067277 100644 --- a/bot/exts/evergreen/connect_four.py +++ b/bot/exts/evergreen/connect_four.py @@ -89,7 +89,7 @@ class Game: await self.message.edit(content=None, embed=embed) async def game_over(self, winner: discord.user, loser: discord.user) -> None: - """Removes games from list of current games and announces to public chat.""" + """Announces to public chat.""" await self.channel.send(f"Game Over! {winner.mention} won against {loser.mention}") await self.print_grid() -- cgit v1.2.3 From 79fb946c55b9f3049b0e2f0c5fd38f2ee2ee5add Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Sat, 30 Jan 2021 17:22:45 +0530 Subject: Line 114, 115 was cuasing error as a set was being sent to it instead discord.member object --- bot/exts/evergreen/connect_four.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/connect_four.py b/bot/exts/evergreen/connect_four.py index 19067277..858caf78 100644 --- a/bot/exts/evergreen/connect_four.py +++ b/bot/exts/evergreen/connect_four.py @@ -113,8 +113,8 @@ class Game: if self.check_win(coords, 1 if self.player_active == self.player1 else 2): await self.game_over( - self.bot.user if isinstance(self.player_active, AI) else {self.player_active}, - self.bot.user if isinstance(self.player_inactive, AI) else {self.player_inactive}, + self.bot.user if isinstance(self.player_active, AI) else self.player_active, + self.bot.user if isinstance(self.player_inactive, AI) else self.player_inactive, ) return -- cgit v1.2.3 From 9675434e1437b4c182e1eccbeeba9aa064ce779b Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Sat, 30 Jan 2021 17:23:37 +0530 Subject: REmove repeating code --- bot/exts/evergreen/connect_four.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/connect_four.py b/bot/exts/evergreen/connect_four.py index 858caf78..30eb0ff9 100644 --- a/bot/exts/evergreen/connect_four.py +++ b/bot/exts/evergreen/connect_four.py @@ -141,12 +141,11 @@ class Game: await self.channel.send(f"{self.player_active.mention}, you took too long. Game over!") return else: + await message.delete() if str(reaction.emoji) == CROSS_EMOJI: - await message.delete() await self.channel.send(f"{self.player_active.user} surrendered. Game over!") return - - await message.delete() + await self.message.remove_reaction(reaction, user) column_num = self.unicode_numbers.index(str(reaction.emoji)) -- cgit v1.2.3 From 630f46a197c89a137e89c0bba526090c8f0ace33 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Sat, 30 Jan 2021 17:25:45 +0530 Subject: Error while sending surrender message as it was taking .user instead of .mention --- bot/exts/evergreen/connect_four.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/connect_four.py b/bot/exts/evergreen/connect_four.py index 30eb0ff9..7ad0d723 100644 --- a/bot/exts/evergreen/connect_four.py +++ b/bot/exts/evergreen/connect_four.py @@ -82,7 +82,7 @@ class Game: if self.message: await self.message.edit(embed=embed) else: - self.message = await self.channel.send(content='Loading ....') + self.message = await self.channel.send(content='Loading...') for emoji in self.unicode_numbers: await self.message.add_reaction(emoji) await self.message.add_reaction(CROSS_EMOJI) @@ -143,7 +143,7 @@ class Game: else: await message.delete() if str(reaction.emoji) == CROSS_EMOJI: - await self.channel.send(f"{self.player_active.user} surrendered. Game over!") + await self.channel.send(f"{self.player_active.mention} surrendered. Game over!") return await self.message.remove_reaction(reaction, user) -- cgit v1.2.3 From 46ca17d5fe41e704e40e22839e9d8b21c9a7b659 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Sun, 31 Jan 2021 04:55:57 +0530 Subject: Let game_over function handle all gane over instances --- bot/exts/evergreen/connect_four.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/connect_four.py b/bot/exts/evergreen/connect_four.py index 7ad0d723..31b85bbe 100644 --- a/bot/exts/evergreen/connect_four.py +++ b/bot/exts/evergreen/connect_four.py @@ -88,9 +88,14 @@ class Game: await self.message.add_reaction(CROSS_EMOJI) await self.message.edit(content=None, embed=embed) - async def game_over(self, winner: discord.user, loser: discord.user) -> None: + async def game_over(self, action: str, player1: discord.user, player2: discord.user) -> None: """Announces to public chat.""" - await self.channel.send(f"Game Over! {winner.mention} won against {loser.mention}") + if action == "win": + await self.channel.send(f"Game Over! {player1.mention} won against {player2.mention}") + elif action == "draw": + await self.channel.send(f"Game Over! {player1.mention} {player2.mention} It's A Draw :tada:") + elif action == "quit": + await self.channel.send(f"{self.player1.mention} surrendered. Game over!") await self.print_grid() async def start_game(self) -> None: @@ -103,8 +108,11 @@ class Game: if isinstance(self.player_active, AI): coords = self.player_active.play() if not coords: - await self.channel.send("Game Over! It's A Draw :tada:") - await self.print_grid() + await self.game_over( + "draw", + self.bot.user if isinstance(self.player_active, AI) else self.player_active, + self.bot.user if isinstance(self.player_inactive, AI) else self.player_inactive, + ) else: coords = await self.player_turn() @@ -113,6 +121,7 @@ class Game: if self.check_win(coords, 1 if self.player_active == self.player1 else 2): await self.game_over( + "win", self.bot.user if isinstance(self.player_active, AI) else self.player_active, self.bot.user if isinstance(self.player_inactive, AI) else self.player_inactive, ) @@ -143,9 +152,9 @@ class Game: else: await message.delete() if str(reaction.emoji) == CROSS_EMOJI: - await self.channel.send(f"{self.player_active.mention} surrendered. Game over!") + await self.game_over("quit", self.player_active, self.player_inactive) return - + await self.message.remove_reaction(reaction, user) column_num = self.unicode_numbers.index(str(reaction.emoji)) -- cgit v1.2.3 From 259686206e71496131872788a746186ee34920d8 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Sun, 31 Jan 2021 05:05:54 +0530 Subject: Add ability to choose ai token while playing against ai --- bot/exts/evergreen/connect_four.py | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/connect_four.py b/bot/exts/evergreen/connect_four.py index 31b85bbe..50632c1b 100644 --- a/bot/exts/evergreen/connect_four.py +++ b/bot/exts/evergreen/connect_four.py @@ -338,6 +338,15 @@ class ConnectFour(commands.Cog): """Check if someone is already in a game.""" return any(player in (game.player1, game.player2) for game in self.games) + @staticmethod + def check_emojis(e1: EMOJI_CHECK, e2: EMOJI_CHECK) -> typing.Tuple[bool, typing.Optional[str]]: + """Validate the emojis, the user put.""" + if isinstance(e1, str) and len(e1) > 1: + return False, e1 + if isinstance(e2, str) and len(e2) > 1: + return False, e2 + return True, None + async def _play_game( self, ctx: commands.Context, @@ -381,10 +390,9 @@ class ConnectFour(commands.Cog): The game will start once someone has reacted. All inputs will be through reactions. """ - if isinstance(emoji1, str) and len(emoji1) > 1: - raise commands.EmojiNotFound(emoji1) - if isinstance(emoji2, str) and len(emoji2) > 1: - raise commands.EmojiNotFound(emoji2) + check, emoji = self.check_emojis(emoji1, emoji2) + if not check: + raise commands.EmojiNotFound(emoji) check_author_result = await self.check_author(ctx, board_size) if not check_author_result: @@ -432,15 +440,19 @@ class ConnectFour(commands.Cog): self, ctx: commands.Context, board_size: int = 7, - emoji1: EMOJI_CHECK = "\U0001f535" + emoji1: EMOJI_CHECK = "\U0001f535", + emoji2: EMOJI_CHECK = "\U0001f534" ) -> None: """Play Connect Four against a computer player.""" - if isinstance(emoji1, str) and len(emoji1) > 1: - raise commands.EmojiNotFound(emoji1) + check, emoji = self.check_emojis(emoji1, emoji2) + if not check: + raise commands.EmojiNotFound(emoji) + check_author_result = await self.check_author(ctx, board_size) if not check_author_result: return - await self._play_game(ctx, None, board_size, str(emoji1), ":red_circle:") + + await self._play_game(ctx, None, board_size, str(emoji1), str(emoji2)) def setup(bot: commands.Bot) -> None: -- cgit v1.2.3 From 45af7ff6803e75d70be8d78e232b3d30803ae65d Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Sun, 31 Jan 2021 05:13:35 +0530 Subject: Add mod_meta and mod_tools channels to whitelisted --- bot/constants.py | 2 ++ bot/exts/evergreen/issues.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/constants.py b/bot/constants.py index ce1ca29a..1234ef3b 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -116,6 +116,8 @@ class Channels(NamedTuple): message_log = 467752170159079424 mod_alerts = 473092532147060736 modlog = 282638479504965634 + mod_meta = 775412552795947058 + mod_tools = 775413915391098921 off_topic_0 = 291284109232308226 off_topic_1 = 463035241142026251 off_topic_2 = 463035268514185226 diff --git a/bot/exts/evergreen/issues.py b/bot/exts/evergreen/issues.py index 72d88d04..f24e0717 100644 --- a/bot/exts/evergreen/issues.py +++ b/bot/exts/evergreen/issues.py @@ -26,7 +26,7 @@ if GITHUB_TOKEN := Tokens.github: WHITELISTED_CATEGORIES = ( Categories.devprojects, Categories.media, Categories.development ) -WHITELISTED_CHANNELS_ON_MESSAGE = (Channels.organisation,) +WHITELISTED_CHANNELS_ON_MESSAGE = (Channels.organisation, Channels.mod_meta, Channels.mod_tools) CODE_BLOCK_RE = re.compile( r"^`([^`\n]+)`" # Inline codeblock -- cgit v1.2.3 From f5eae5bec548bc1e450af7f07387531b80869f84 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Sun, 31 Jan 2021 05:26:23 +0530 Subject: Remove unused imports --- bot/exts/evergreen/status_codes.py | 2 -- 1 file changed, 2 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/status_codes.py b/bot/exts/evergreen/status_codes.py index eebc23af..473e778c 100644 --- a/bot/exts/evergreen/status_codes.py +++ b/bot/exts/evergreen/status_codes.py @@ -1,8 +1,6 @@ -import re from http import HTTPStatus import discord -from discord import HTTPException from discord.ext import commands -- cgit v1.2.3 From c60c8471b4e0cb9b54bee80fd43c75c4a2e75b76 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Sun, 31 Jan 2021 15:13:58 +0530 Subject: Fix import order --- bot/exts/evergreen/cheatsheet.py | 93 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 bot/exts/evergreen/cheatsheet.py (limited to 'bot') diff --git a/bot/exts/evergreen/cheatsheet.py b/bot/exts/evergreen/cheatsheet.py new file mode 100644 index 00000000..3a689005 --- /dev/null +++ b/bot/exts/evergreen/cheatsheet.py @@ -0,0 +1,93 @@ +import random +import re +import typing as t +from urllib.parse import quote_plus + +from discord import Embed +from discord.ext import commands +from discord.ext.commands import BucketType, Context + +from bot.constants import Channels, Colours, ERROR_REPLIES + +ERROR_MESSAGE = """ +Unknown cheat sheet. Please try to reformulate your query. + +**Examples**: +```md +.cht read json +.cht hello world +.cht lambda +``` +If the problem persists send a message in <#{channel}> +""" + + +class ChtSh(commands.Cog): + """Commands that sends a result of a cht.sh search in code blocks.""" + + def __init__(self, bot: commands.Bot): + self.bot = bot + + @staticmethod + def fmt_error_embed() -> Embed: + """If the cht.sh search returned 404, overwrite it to send a custom error embed.""" + embed = Embed(colour=Colours.soft_red) + embed.title = random.choice(ERROR_REPLIES) + embed.description = ERROR_MESSAGE.format(channel=Channels.dev_contrib) + return embed + + def result_fmt(self, url: str, body_text: str) -> t.Tuple[bool, t.Union[str, Embed]]: + """Format Result.""" + if body_text.startswith("# 404 NOT FOUND"): + embed = self.fmt_error_embed() + return True, embed + + body_space = min(1986 - len(url), 1000) + + if len(body_text) > body_space: + description = f"**Result Of cht.sh**\n" \ + f"```python\n{body_text[:body_space]}\n" \ + f"... (truncated - too many lines)```\n" \ + f"Full results: {url} " + else: + description = f"**Result Of cht.sh**\n" \ + f"```python\n{body_text}```\n" \ + f"{url}" + return False, description + + @commands.command( + name="cheat", + aliases=("cht.sh", "cheatsheet", "cheat-sheet", "cht"), + ) + @commands.cooldown(1, 10, BucketType.user) + async def cheat_sheet( + self, ctx: Context, *search_terms: str + ) -> None: + """ + Search cheat.sh. + + Gets a post from https://cheat.sh/python/ by default. + Usage: + --> .cht read json + """ + url = f'https://cheat.sh/python/{quote_plus(" ".join(search_terms))}' + headers = { + 'User-Agent': 'curl/7.68.0' + } + + escape_tt = str.maketrans({"`": "\\`"}) + ansi_re = re.compile(r"\x1b\[.*?m") + + async with self.bot.http_session.get(url, headers=headers) as response: + result = ansi_re.sub("", await response.text()).translate(escape_tt) + + is_embed, desciprtion = self.result_fmt(url, result) + if is_embed: + await ctx.send(embed=desciprtion) + else: + await ctx.send(content=desciprtion) + + +def setup(bot: commands.Bot) -> None: + """Load the ChtSh cog.""" + bot.add_cog(ChtSh(bot)) -- cgit v1.2.3 From a602361492cc653f8fae82a3b30f36b232ba5024 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Mon, 1 Feb 2021 05:18:28 +0530 Subject: Rename cog CheatSheet ; Change Embed code to a single constructor ; remove headers as chubin/cheat.sh#280 got merged ; improve error embed docstrings --- bot/exts/evergreen/cheatsheet.py | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/cheatsheet.py b/bot/exts/evergreen/cheatsheet.py index 3a689005..211b3246 100644 --- a/bot/exts/evergreen/cheatsheet.py +++ b/bot/exts/evergreen/cheatsheet.py @@ -22,7 +22,7 @@ If the problem persists send a message in <#{channel}> """ -class ChtSh(commands.Cog): +class CheatSheet(commands.Cog): """Commands that sends a result of a cht.sh search in code blocks.""" def __init__(self, bot: commands.Bot): @@ -30,10 +30,17 @@ class ChtSh(commands.Cog): @staticmethod def fmt_error_embed() -> Embed: - """If the cht.sh search returned 404, overwrite it to send a custom error embed.""" - embed = Embed(colour=Colours.soft_red) - embed.title = random.choice(ERROR_REPLIES) - embed.description = ERROR_MESSAGE.format(channel=Channels.dev_contrib) + """ + Format the Error Embed. + + If the cht.sh search returned 404, overwrite it to send a custom error embed. + link -> https://github.com/chubin/cheat.sh/issues/198 + """ + embed = Embed( + title=random.choice(ERROR_REPLIES), + description=ERROR_MESSAGE.format(channel=Channels.dev_contrib), + colour=Colours.soft_red + ) return embed def result_fmt(self, url: str, body_text: str) -> t.Tuple[bool, t.Union[str, Embed]]: @@ -71,23 +78,20 @@ class ChtSh(commands.Cog): --> .cht read json """ url = f'https://cheat.sh/python/{quote_plus(" ".join(search_terms))}' - headers = { - 'User-Agent': 'curl/7.68.0' - } escape_tt = str.maketrans({"`": "\\`"}) ansi_re = re.compile(r"\x1b\[.*?m") - async with self.bot.http_session.get(url, headers=headers) as response: + async with self.bot.http_session.get(url) as response: result = ansi_re.sub("", await response.text()).translate(escape_tt) - is_embed, desciprtion = self.result_fmt(url, result) + is_embed, description = self.result_fmt(url, result) if is_embed: - await ctx.send(embed=desciprtion) + await ctx.send(embed=description) else: - await ctx.send(content=desciprtion) + await ctx.send(content=description) def setup(bot: commands.Bot) -> None: - """Load the ChtSh cog.""" - bot.add_cog(ChtSh(bot)) + """Load the CheatSheet cog.""" + bot.add_cog(CheatSheet(bot)) -- cgit v1.2.3 From c87f6e0561bbeb6510292a0b09a829aa6fa290a7 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Mon, 1 Feb 2021 05:21:32 +0530 Subject: rename the cog to HTTPStatusCodes --- bot/exts/evergreen/status_codes.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/status_codes.py b/bot/exts/evergreen/status_codes.py index 473e778c..19375657 100644 --- a/bot/exts/evergreen/status_codes.py +++ b/bot/exts/evergreen/status_codes.py @@ -4,7 +4,7 @@ import discord from discord.ext import commands -class StatusCats(commands.Cog): +class HTTPStatusCodes(commands.Cog): """Commands that give HTTP statuses described and visualized by cats and dogs.""" def __init__(self, bot: commands.Bot): @@ -57,5 +57,5 @@ class StatusCats(commands.Cog): def setup(bot: commands.Bot) -> None: - """Load the StatusCats cog.""" - bot.add_cog(StatusCats(bot)) + """Load the HTTPStatusCodes cog.""" + bot.add_cog(HTTPStatusCodes(bot)) -- cgit v1.2.3 From e32182ee7000cea8a49d41605bb01563c0d68800 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Mon, 1 Feb 2021 05:28:35 +0530 Subject: Add similar repsonse.status check to too, and instead of ValueError raise NotImplemented error if the status is not implemented yet but is a valid status code --- bot/exts/evergreen/status_codes.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/status_codes.py b/bot/exts/evergreen/status_codes.py index 19375657..bfc4bb1a 100644 --- a/bot/exts/evergreen/status_codes.py +++ b/bot/exts/evergreen/status_codes.py @@ -23,13 +23,18 @@ class HTTPStatusCodes(commands.Cog): try: HTTPStatus(code) + async with self.bot.http_session.get( + f'https://http.cat/{code}.jpg', + allow_redirects=False + ) as response: + if response.status != 404: + embed.set_image(url=f'https://http.cat/{code}.jpg') + else: + raise NotImplementedError except ValueError: embed.set_footer(text='Inputted status code does not exist.') - else: - embed.set_image(url=f'https://http.cat/{code}.jpg') - finally: await ctx.send(embed=embed) @@ -47,11 +52,14 @@ class HTTPStatusCodes(commands.Cog): if response.status != 302: embed.set_image(url=f'https://httpstatusdogs.com/img/{code}.jpg') else: - raise ValueError + raise NotImplementedError except ValueError: embed.set_footer(text='Inputted status code does not exist.') + except NotImplementedError: + embed.set_footer(text='Inputted status code is not implemented by httpstatusdogs.com yet.') + finally: await ctx.send(embed=embed) -- cgit v1.2.3 From 8a92054bab4c3dbd0e42d633d11a87461e1189e1 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Mon, 1 Feb 2021 05:31:48 +0530 Subject: Remove brackets from .join --- bot/exts/evergreen/issues.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/issues.py b/bot/exts/evergreen/issues.py index f24e0717..72ca6de4 100644 --- a/bot/exts/evergreen/issues.py +++ b/bot/exts/evergreen/issues.py @@ -189,7 +189,7 @@ class Issues(commands.Cog): if message_repo_issue_map: for repo_issue in message_repo_issue_map: - if not self.check_in_block(message, " ".join([*repo_issue])): + if not self.check_in_block(message, " ".join(repo_issue)): result = await self.fetch_issues({repo_issue[1]}, repo_issue[0], "python-discord") if isinstance(result, list): links.extend(result) -- cgit v1.2.3 From 29c84ad7cc6729c0887f49206ade8f98e2655fd1 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Mon, 1 Feb 2021 13:37:04 +0530 Subject: Remove the use of globals and instead use class variables --- bot/exts/evergreen/connect_four.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/connect_four.py b/bot/exts/evergreen/connect_four.py index 50632c1b..48473d30 100644 --- a/bot/exts/evergreen/connect_four.py +++ b/bot/exts/evergreen/connect_four.py @@ -6,7 +6,6 @@ from functools import partial import discord from discord.ext import commands -EMOJI_TOKENS = [":white_circle:", ":blue_circle:", ":red_circle:"] NUMBERS = [ ":one:", ":two:", @@ -44,13 +43,15 @@ class Game: channel: discord.TextChannel, player1: discord.Member, player2: typing.Optional[discord.Member], - size: int = 7, + tokens: typing.List[str], + size: int = 7 ) -> None: self.bot = bot self.channel = channel self.player1 = player1 self.player2 = player2 or AI(self.bot, game=self) + self.tokens = tokens self.grid = self.generate_board(size) self.grid_size = size @@ -74,7 +75,7 @@ class Game: f' VS {self.bot.user.display_name if isinstance(self.player2, AI) else self.player2.display_name}' ) - rows = [" ".join(EMOJIS[s] for s in row) for row in self.grid] + rows = [" ".join(self.tokens[s] for s in row) for row in self.grid] first_row = " ".join(x for x in NUMBERS[:self.grid_size]) formatted_grid = "\n".join([first_row] + rows) embed = discord.Embed(title=title, description=formatted_grid) @@ -276,6 +277,8 @@ class ConnectFour(commands.Cog): self.games: typing.List[Game] = [] self.waiting: typing.List[discord.Member] = [] + self.tokens = [":white_circle:", ":blue_circle:", ":red_circle:"] + self.max_board_size = 9 self.min_board_size = 5 @@ -356,11 +359,10 @@ class ConnectFour(commands.Cog): emoji2: str ) -> None: """Helper for playing a game of connect four.""" - global EMOJIS - EMOJIS = [":white_circle:", str(emoji1), str(emoji2)] + self.tokens = [":white_circle:", str(emoji1), str(emoji2)] try: - game = Game(self.bot, ctx.channel, ctx.author, user, size=board_size) + game = Game(self.bot, ctx.channel, ctx.author, user, self.tokens, size=board_size) self.games.append(game) await game.start_game() self.games.remove(game) -- cgit v1.2.3 From 4239b1d07cd0bba543aca8e7c77cee1d8f437b14 Mon Sep 17 00:00:00 2001 From: Hassan Abouelela <47495861+HassanAbouelela@users.noreply.github.com> Date: Mon, 1 Feb 2021 11:47:52 +0300 Subject: Fixes Issue Matching Regex Changes the automatic issue matching regex to make it work for repos at the very beginning of messages. --- bot/exts/evergreen/issues.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/issues.py b/bot/exts/evergreen/issues.py index 72ca6de4..73ebe547 100644 --- a/bot/exts/evergreen/issues.py +++ b/bot/exts/evergreen/issues.py @@ -184,7 +184,7 @@ class Issues(commands.Cog): ): return - message_repo_issue_map = re.findall(fr".+?({self.repo_regex})#(\d+)", message.content) + message_repo_issue_map = re.findall(fr"({self.repo_regex})#(\d+)", message.content) links = [] if message_repo_issue_map: -- cgit v1.2.3 From 4b8f5789aa0c9f6ce005273ed1affdbc3a87c16a Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Mon, 1 Feb 2021 14:46:55 +0530 Subject: Add check if game is not intialized --- bot/exts/evergreen/connect_four.py | 1 + 1 file changed, 1 insertion(+) (limited to 'bot') diff --git a/bot/exts/evergreen/connect_four.py b/bot/exts/evergreen/connect_four.py index 48473d30..bf604e2a 100644 --- a/bot/exts/evergreen/connect_four.py +++ b/bot/exts/evergreen/connect_four.py @@ -360,6 +360,7 @@ class ConnectFour(commands.Cog): ) -> None: """Helper for playing a game of connect four.""" self.tokens = [":white_circle:", str(emoji1), str(emoji2)] + game = None # if game fails to intialize in try...except try: game = Game(self.bot, ctx.channel, ctx.author, user, self.tokens, size=board_size) -- cgit v1.2.3 From 5c4cbbeeb5fd9e7f7c651b24b2b1d3bdbcc55110 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Tue, 2 Feb 2021 05:09:29 +0530 Subject: Make use of constants --- bot/exts/evergreen/cheatsheet.py | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/cheatsheet.py b/bot/exts/evergreen/cheatsheet.py index 211b3246..4191a83f 100644 --- a/bot/exts/evergreen/cheatsheet.py +++ b/bot/exts/evergreen/cheatsheet.py @@ -7,20 +7,25 @@ from discord import Embed from discord.ext import commands from discord.ext.commands import BucketType, Context +from bot import constants from bot.constants import Channels, Colours, ERROR_REPLIES -ERROR_MESSAGE = """ +ERROR_MESSAGE = f""" Unknown cheat sheet. Please try to reformulate your query. **Examples**: ```md -.cht read json -.cht hello world -.cht lambda +{constants.Client.prefix}cht read json +{constants.Client.prefix}cht hello world +{constants.Client.prefix}cht lambda ``` -If the problem persists send a message in <#{channel}> +If the problem persists send a message in <#{Channels.dev_contrib}> """ +URL = 'https://cheat.sh/python/{search}' +ESCAPE_TT = str.maketrans({"`": "\\`"}) +ANSI_RE = re.compile(r"\x1b\[.*?m") + class CheatSheet(commands.Cog): """Commands that sends a result of a cht.sh search in code blocks.""" @@ -38,7 +43,7 @@ class CheatSheet(commands.Cog): """ embed = Embed( title=random.choice(ERROR_REPLIES), - description=ERROR_MESSAGE.format(channel=Channels.dev_contrib), + description=ERROR_MESSAGE, colour=Colours.soft_red ) return embed @@ -67,9 +72,7 @@ class CheatSheet(commands.Cog): aliases=("cht.sh", "cheatsheet", "cheat-sheet", "cht"), ) @commands.cooldown(1, 10, BucketType.user) - async def cheat_sheet( - self, ctx: Context, *search_terms: str - ) -> None: + async def cheat_sheet(self, ctx: Context, *search_terms: str) -> None: """ Search cheat.sh. @@ -77,15 +80,15 @@ class CheatSheet(commands.Cog): Usage: --> .cht read json """ - url = f'https://cheat.sh/python/{quote_plus(" ".join(search_terms))}' - - escape_tt = str.maketrans({"`": "\\`"}) - ansi_re = re.compile(r"\x1b\[.*?m") - - async with self.bot.http_session.get(url) as response: - result = ansi_re.sub("", await response.text()).translate(escape_tt) - - is_embed, description = self.result_fmt(url, result) + async with self.bot.http_session.get( + URL.format(search=quote_plus(" ".join(search_terms))) + ) as response: + result = ANSI_RE.sub("", await response.text()).translate(ESCAPE_TT) + + is_embed, description = self.result_fmt( + URL.format(search=quote_plus(" ".join(search_terms))), + result + ) if is_embed: await ctx.send(embed=description) else: -- cgit v1.2.3 From 2631004f7d1467bc81090ac481de78cbfe7978e5 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Tue, 2 Feb 2021 05:14:34 +0530 Subject: Add override_in_channel deco --- bot/exts/evergreen/cheatsheet.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/cheatsheet.py b/bot/exts/evergreen/cheatsheet.py index 4191a83f..c83af839 100644 --- a/bot/exts/evergreen/cheatsheet.py +++ b/bot/exts/evergreen/cheatsheet.py @@ -8,7 +8,8 @@ from discord.ext import commands from discord.ext.commands import BucketType, Context from bot import constants -from bot.constants import Channels, Colours, ERROR_REPLIES +from bot.constants import Channels, Colours, ERROR_REPLIES, WHITELISTED_CHANNELS +from bot.utils.decorators import override_in_channel ERROR_MESSAGE = f""" Unknown cheat sheet. Please try to reformulate your query. @@ -71,6 +72,7 @@ class CheatSheet(commands.Cog): name="cheat", aliases=("cht.sh", "cheatsheet", "cheat-sheet", "cht"), ) + @override_in_channel(WHITELISTED_CHANNELS) @commands.cooldown(1, 10, BucketType.user) async def cheat_sheet(self, ctx: Context, *search_terms: str) -> None: """ -- cgit v1.2.3 From aee64f82f5a97a4bdd32c6d6d66f6f0eb8ef51f8 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Tue, 2 Feb 2021 05:23:34 +0530 Subject: Add not Implemented error handler for .status cat command --- bot/exts/evergreen/status_codes.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'bot') diff --git a/bot/exts/evergreen/status_codes.py b/bot/exts/evergreen/status_codes.py index bfc4bb1a..ff2ac9e1 100644 --- a/bot/exts/evergreen/status_codes.py +++ b/bot/exts/evergreen/status_codes.py @@ -35,6 +35,9 @@ class HTTPStatusCodes(commands.Cog): except ValueError: embed.set_footer(text='Inputted status code does not exist.') + except NotImplementedError: + embed.set_footer(text='Inputted status code is not implemented by http.cat yet.') + finally: await ctx.send(embed=embed) -- cgit v1.2.3 From 3e884eaa43b78b433a470aaff39b03a0f6c2b3c2 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Tue, 2 Feb 2021 06:05:46 +0530 Subject: Allow cht.sh command to be used in occupied help channels --- bot/constants.py | 11 +++++------ bot/exts/evergreen/cheatsheet.py | 13 +++++++++---- 2 files changed, 14 insertions(+), 10 deletions(-) (limited to 'bot') diff --git a/bot/constants.py b/bot/constants.py index 1d41a53e..23865272 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -104,12 +104,6 @@ class Channels(NamedTuple): devlog = int(environ.get("CHANNEL_DEVLOG", 622895325144940554)) dev_contrib = 635950537262759947 dev_branding = 753252897059373066 - help_0 = 303906576991780866 - help_1 = 303906556754395136 - help_2 = 303906514266226689 - help_3 = 439702951246692352 - help_4 = 451312046647148554 - help_5 = 454941769734422538 helpers = 385474242440986624 message_log = 467752170159079424 mod_alerts = 473092532147060736 @@ -128,6 +122,10 @@ class Channels(NamedTuple): voice_chat_1 = 799647045886541885 +class Categories(NamedTuple): + help_in_use = 696958401460043776 + + class Client(NamedTuple): name = "Sir Lancebot" guild = int(environ.get("BOT_GUILD", 267624335836053506)) @@ -249,6 +247,7 @@ class Roles(NamedTuple): rockstars = 458226413825294336 core_developers = 587606783669829632 events_lead = 778361735739998228 + everyone = 267624335836053506 class Tokens(NamedTuple): diff --git a/bot/exts/evergreen/cheatsheet.py b/bot/exts/evergreen/cheatsheet.py index c83af839..83098c76 100644 --- a/bot/exts/evergreen/cheatsheet.py +++ b/bot/exts/evergreen/cheatsheet.py @@ -3,13 +3,13 @@ import re import typing as t from urllib.parse import quote_plus -from discord import Embed +from discord import Embed, utils from discord.ext import commands from discord.ext.commands import BucketType, Context from bot import constants -from bot.constants import Channels, Colours, ERROR_REPLIES, WHITELISTED_CHANNELS -from bot.utils.decorators import override_in_channel +from bot.constants import Categories, Channels, Colours, ERROR_REPLIES, Roles, WHITELISTED_CHANNELS +from bot.utils.decorators import with_role ERROR_MESSAGE = f""" Unknown cheat sheet. Please try to reformulate your query. @@ -72,8 +72,8 @@ class CheatSheet(commands.Cog): name="cheat", aliases=("cht.sh", "cheatsheet", "cheat-sheet", "cht"), ) - @override_in_channel(WHITELISTED_CHANNELS) @commands.cooldown(1, 10, BucketType.user) + @with_role(Roles.everyone) async def cheat_sheet(self, ctx: Context, *search_terms: str) -> None: """ Search cheat.sh. @@ -82,6 +82,11 @@ class CheatSheet(commands.Cog): Usage: --> .cht read json """ + category = utils.get(ctx.message.guild.categories, id=Categories.help_in_use) + all_allowed_channels = WHITELISTED_CHANNELS + tuple(category.channels) + if ctx.channel not in all_allowed_channels: + return + async with self.bot.http_session.get( URL.format(search=quote_plus(" ".join(search_terms))) ) as response: -- cgit v1.2.3 From b10b2524a1284f7462f3b0f039827e6d115e7931 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Tue, 2 Feb 2021 06:16:38 +0530 Subject: Improve category check code --- bot/exts/evergreen/cheatsheet.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/cheatsheet.py b/bot/exts/evergreen/cheatsheet.py index 83098c76..abc5306b 100644 --- a/bot/exts/evergreen/cheatsheet.py +++ b/bot/exts/evergreen/cheatsheet.py @@ -3,7 +3,7 @@ import re import typing as t from urllib.parse import quote_plus -from discord import Embed, utils +from discord import Embed from discord.ext import commands from discord.ext.commands import BucketType, Context @@ -82,9 +82,10 @@ class CheatSheet(commands.Cog): Usage: --> .cht read json """ - category = utils.get(ctx.message.guild.categories, id=Categories.help_in_use) - all_allowed_channels = WHITELISTED_CHANNELS + tuple(category.channels) - if ctx.channel not in all_allowed_channels: + if not ( + ctx.channel.category.id == Categories.help_in_use + or ctx.channel.id in WHITELISTED_CHANNELS + ): return async with self.bot.http_session.get( -- cgit v1.2.3 From 5190f5b8576267807dd6a4920964d684f0d572a4 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Tue, 2 Feb 2021 06:17:58 +0530 Subject: everyone -> everyone_role and remove developers role --- bot/constants.py | 3 +-- bot/exts/evergreen/cheatsheet.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'bot') diff --git a/bot/constants.py b/bot/constants.py index 23865272..8e210ad3 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -236,7 +236,6 @@ class Roles(NamedTuple): announcements = 463658397560995840 champion = 430492892331769857 contributor = 295488872404484098 - developer = 352427296948486144 devops = 409416496733880320 jammer = 423054537079783434 moderator = 267629731250176001 @@ -247,7 +246,7 @@ class Roles(NamedTuple): rockstars = 458226413825294336 core_developers = 587606783669829632 events_lead = 778361735739998228 - everyone = 267624335836053506 + everyone_role = 267624335836053506 class Tokens(NamedTuple): diff --git a/bot/exts/evergreen/cheatsheet.py b/bot/exts/evergreen/cheatsheet.py index abc5306b..f650e3b0 100644 --- a/bot/exts/evergreen/cheatsheet.py +++ b/bot/exts/evergreen/cheatsheet.py @@ -73,7 +73,7 @@ class CheatSheet(commands.Cog): aliases=("cht.sh", "cheatsheet", "cheat-sheet", "cht"), ) @commands.cooldown(1, 10, BucketType.user) - @with_role(Roles.everyone) + @with_role(Roles.everyone_role) async def cheat_sheet(self, ctx: Context, *search_terms: str) -> None: """ Search cheat.sh. -- cgit v1.2.3 From 5e55ea1dbfd652c10999c88d1c32aebd1be768f0 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Thu, 4 Feb 2021 05:23:54 +0530 Subject: Make use of constants in the url --- bot/exts/evergreen/status_codes.py | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/status_codes.py b/bot/exts/evergreen/status_codes.py index ff2ac9e1..874c87eb 100644 --- a/bot/exts/evergreen/status_codes.py +++ b/bot/exts/evergreen/status_codes.py @@ -3,6 +3,9 @@ from http import HTTPStatus import discord from discord.ext import commands +HTTP_DOG_URL = "https://httpstatusdogs.com/img/{code}.jpg" +HTTP_CAT_URL = "https://http.cat/{code}.jpg" + class HTTPStatusCodes(commands.Cog): """Commands that give HTTP statuses described and visualized by cats and dogs.""" @@ -16,19 +19,17 @@ class HTTPStatusCodes(commands.Cog): if not ctx.invoked_subcommand: await ctx.send_help(ctx.command) - @http_status_group.command(aliases=['cat']) + @http_status_group.command(name='cat') async def http_cat(self, ctx: commands.Context, code: int) -> None: """Sends an embed with an image of a cat, portraying the status code.""" embed = discord.Embed(title=f'**Status: {code}**') + url = HTTP_CAT_URL.format(code=code) try: HTTPStatus(code) - async with self.bot.http_session.get( - f'https://http.cat/{code}.jpg', - allow_redirects=False - ) as response: + async with self.bot.http_session.get(url, allow_redirects=False) as response: if response.status != 404: - embed.set_image(url=f'https://http.cat/{code}.jpg') + embed.set_image(url=url) else: raise NotImplementedError @@ -41,19 +42,17 @@ class HTTPStatusCodes(commands.Cog): finally: await ctx.send(embed=embed) - @http_status_group.command(aliases=['dog']) + @http_status_group.command(name='dog') async def http_dog(self, ctx: commands.Context, code: int) -> None: """Sends an embed with an image of a dog, portraying the status code.""" embed = discord.Embed(title=f'**Status: {code}**') + url = HTTP_DOG_URL.format(code=code) try: HTTPStatus(code) - async with self.bot.http_session.get( - f'https://httpstatusdogs.com/img/{code}.jpg', - allow_redirects=False - ) as response: + async with self.bot.http_session.get(url, allow_redirects=False) as response: if response.status != 302: - embed.set_image(url=f'https://httpstatusdogs.com/img/{code}.jpg') + embed.set_image(url=url) else: raise NotImplementedError -- cgit v1.2.3 From 4687f3d142a40fecc8d851e598dabb6c474059f1 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Thu, 4 Feb 2021 17:28:03 +0530 Subject: Intial Commit; Change secret functionality and fix member intents issue --- bot/exts/valentines/be_my_valentine.py | 70 +++++++++------------------------- 1 file changed, 17 insertions(+), 53 deletions(-) (limited to 'bot') diff --git a/bot/exts/valentines/be_my_valentine.py b/bot/exts/valentines/be_my_valentine.py index 4db4d191..818d539a 100644 --- a/bot/exts/valentines/be_my_valentine.py +++ b/bot/exts/valentines/be_my_valentine.py @@ -2,13 +2,13 @@ import logging import random from json import load from pathlib import Path -from typing import Optional, Tuple +from typing import Tuple import discord from discord.ext import commands from discord.ext.commands.cooldowns import BucketType -from bot.constants import Channels, Client, Colours, Lovefest, Month +from bot.constants import Channels, Colours, Lovefest, Month from bot.utils.decorators import in_month log = logging.getLogger(__name__) @@ -70,15 +70,14 @@ class BeMyValentine(commands.Cog): @commands.cooldown(1, 1800, BucketType.user) @commands.group(name='bemyvalentine', invoke_without_command=True) async def send_valentine( - self, ctx: commands.Context, user: Optional[discord.Member] = None, *, valentine_type: str = None + self, ctx: commands.Context, user: discord.Member, *, valentine_type: str = None ) -> None: """ Send a valentine to user, if specified, or to a random user with the lovefest role. - syntax: .bemyvalentine [user](optional) [p/poem/c/compliment/or you can type your own valentine message] + syntax: .bemyvalentine [user] [p/poem/c/compliment/or you can type your own valentine message] (optional) - example: .bemyvalentine (sends valentine as a poem or a compliment to a random user) example: .bemyvalentine Iceman#6508 p (sends a poem to Iceman) example: .bemyvalentine Iceman Hey I love you, wanna hang around ? (sends the custom message to Iceman) NOTE : AVOID TAGGING THE USER MOST OF THE TIMES.JUST TRIM THE '@' when using this command. @@ -88,26 +87,18 @@ class BeMyValentine(commands.Cog): msg = "You are supposed to use this command in the server." return await ctx.send(msg) - if user: - if Lovefest.role_id not in [role.id for role in user.roles]: - message = f"You cannot send a valentine to {user} as he/she does not have the lovefest role!" - return await ctx.send(message) + if Lovefest.role_id not in [role.id for role in user.roles]: + message = f"You cannot send a valentine to {user} as he/she does not have the lovefest role!" + return await ctx.send(message) if user == ctx.author: # Well a user can't valentine himself/herself. return await ctx.send("Come on dude, you can't send a valentine to yourself :expressionless:") emoji_1, emoji_2 = self.random_emoji() - lovefest_role = discord.utils.get(ctx.guild.roles, id=Lovefest.role_id) channel = self.bot.get_channel(Channels.community_bot_commands) valentine, title = self.valentine_check(valentine_type) - if user is None: - author = ctx.author - user = self.random_user(author, lovefest_role.members) - if user is None: - return await ctx.send("There are no users avilable to whome your valentine can be sent.") - embed = discord.Embed( title=f'{emoji_1} {title} {user.display_name} {emoji_2}', description=f'{valentine} \n **{emoji_2}From {ctx.author}{emoji_1}**', @@ -118,47 +109,31 @@ class BeMyValentine(commands.Cog): @commands.cooldown(1, 1800, BucketType.user) @send_valentine.command(name='secret') async def anonymous( - self, ctx: commands.Context, user: Optional[discord.Member] = None, *, valentine_type: str = None + self, ctx: commands.Context, user: discord.Member, *, valentine_type: str = None ) -> None: """ Send an anonymous Valentine via DM to to a user, if specified, or to a random with the lovefest role. - **This command should be DMed to the bot.** - - syntax : .bemyvalentine secret [user](optional) [p/poem/c/compliment/or you can type your own valentine message] + syntax : .bemyvalentine secret [user] [p/poem/c/compliment/or you can type your own valentine message] (optional) - example : .bemyvalentine secret (sends valentine as a poem or a compliment to a random user in DM making you - anonymous) example : .bemyvalentine secret Iceman#6508 p (sends a poem to Iceman in DM making you anonymous) example : .bemyvalentine secret Iceman#6508 Hey I love you, wanna hang around ? (sends the custom message to Iceman in DM making you anonymous) """ - if ctx.guild is not None: - # This command is only DM specific - msg = "You are not supposed to use this command in the server, DM the command to the bot." - return await ctx.send(msg) - - if user: - if Lovefest.role_id not in [role.id for role in user.roles]: - message = f"You cannot send a valentine to {user} as he/she does not have the lovefest role!" - return await ctx.send(message) + if Lovefest.role_id not in [role.id for role in user.roles]: + message = f"You cannot send a valentine to {user} as he/she does not have the lovefest role!" + await ctx.message.delete() + return await ctx.author.send(message) if user == ctx.author: # Well a user cant valentine himself/herself. - return await ctx.send('Come on dude, you cant send a valentine to yourself :expressionless:') + await ctx.message.delete() + return await ctx.author.send('Come on dude, you cant send a valentine to yourself :expressionless:') - guild = self.bot.get_guild(id=Client.guild) emoji_1, emoji_2 = self.random_emoji() - lovefest_role = discord.utils.get(guild.roles, id=Lovefest.role_id) valentine, title = self.valentine_check(valentine_type) - if user is None: - author = ctx.author - user = self.random_user(author, lovefest_role.members) - if user is None: - return await ctx.send("There are no users avilable to whome your valentine can be sent.") - embed = discord.Embed( title=f'{emoji_1}{title} {user.display_name}{emoji_2}', description=f'{valentine} \n **{emoji_2}From anonymous{emoji_1}**', @@ -166,8 +141,9 @@ class BeMyValentine(commands.Cog): ) try: await user.send(embed=embed) + await ctx.message.delete() except discord.Forbidden: - await ctx.author.send(f"{user} has DMs disabled, so I couldn't send the message. Sorry!") + await ctx.send(f"{user} has DMs disabled, so I couldn't send the message. Sorry!") else: await ctx.author.send(f"Your message has been sent to {user}") @@ -190,18 +166,6 @@ class BeMyValentine(commands.Cog): title = 'A message for' return valentine, title - @staticmethod - def random_user(author: discord.Member, members: discord.Member) -> None: - """ - Picks a random member from the list provided in `members`. - - The invoking author is ignored. - """ - if author in members: - members.remove(author) - - return random.choice(members) if members else None - @staticmethod def random_emoji() -> Tuple[str, str]: """Return two random emoji from the module-defined constants.""" -- cgit v1.2.3 From ae518304b130af53846d8cbd425463661dbc068f Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Fri, 5 Feb 2021 06:43:25 +0530 Subject: Fix return statements and return type annotations --- bot/exts/valentines/be_my_valentine.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'bot') diff --git a/bot/exts/valentines/be_my_valentine.py b/bot/exts/valentines/be_my_valentine.py index 818d539a..41959409 100644 --- a/bot/exts/valentines/be_my_valentine.py +++ b/bot/exts/valentines/be_my_valentine.py @@ -85,15 +85,18 @@ class BeMyValentine(commands.Cog): if ctx.guild is None: # This command should only be used in the server msg = "You are supposed to use this command in the server." - return await ctx.send(msg) + await ctx.send(msg) + return if Lovefest.role_id not in [role.id for role in user.roles]: message = f"You cannot send a valentine to {user} as he/she does not have the lovefest role!" - return await ctx.send(message) + await ctx.send(message) + return if user == ctx.author: # Well a user can't valentine himself/herself. - return await ctx.send("Come on dude, you can't send a valentine to yourself :expressionless:") + await ctx.send("Come on dude, you can't send a valentine to yourself :expressionless:") + return emoji_1, emoji_2 = self.random_emoji() channel = self.bot.get_channel(Channels.community_bot_commands) -- cgit v1.2.3 From 1951ce5fe0a2ae3bd8ef27abe68b1abe3b12be28 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Fri, 5 Feb 2021 06:46:48 +0530 Subject: Remove code that requires intents.member set True --- bot/exts/valentines/lovecalculator.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'bot') diff --git a/bot/exts/valentines/lovecalculator.py b/bot/exts/valentines/lovecalculator.py index c75ea6cf..5cc08fed 100644 --- a/bot/exts/valentines/lovecalculator.py +++ b/bot/exts/valentines/lovecalculator.py @@ -11,8 +11,6 @@ from discord import Member from discord.ext import commands from discord.ext.commands import BadArgument, Cog, clean_content -from bot.constants import Roles - log = logging.getLogger(__name__) with Path("bot/resources/valentines/love_matches.json").open(encoding="utf8") as file: @@ -28,7 +26,7 @@ class LoveCalculator(Cog): @commands.command(aliases=('love_calculator', 'love_calc')) @commands.cooldown(rate=1, per=5, type=commands.BucketType.user) - async def love(self, ctx: commands.Context, who: Union[Member, str], whom: Union[Member, str] = None) -> None: + async def love(self, ctx: commands.Context, who: Union[Member, str], whom: Union[Member, str]) -> None: """ Tells you how much the two love each other. @@ -46,13 +44,7 @@ class LoveCalculator(Cog): If you want to use multiple words for one argument, you must include quotes. .love "Zes Vappa" "morning coffee" - - If only one argument is provided, the subject will become one of the helpers at random. """ - if whom is None: - staff = ctx.guild.get_role(Roles.helpers).members - whom = random.choice(staff) - def normalize(arg: Union[Member, str]) -> str: if isinstance(arg, Member): # If we are given a member, return name#discrim without any extra changes -- cgit v1.2.3 From d9a40f8591de1537b38d261e77b42ddc8cbc5688 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Fri, 5 Feb 2021 06:54:02 +0530 Subject: If whom is None, take the user as whom --- bot/exts/valentines/lovecalculator.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'bot') diff --git a/bot/exts/valentines/lovecalculator.py b/bot/exts/valentines/lovecalculator.py index 5cc08fed..966acc82 100644 --- a/bot/exts/valentines/lovecalculator.py +++ b/bot/exts/valentines/lovecalculator.py @@ -4,7 +4,7 @@ import json import logging import random from pathlib import Path -from typing import Union +from typing import Coroutine, Union import discord from discord import Member @@ -26,7 +26,7 @@ class LoveCalculator(Cog): @commands.command(aliases=('love_calculator', 'love_calc')) @commands.cooldown(rate=1, per=5, type=commands.BucketType.user) - async def love(self, ctx: commands.Context, who: Union[Member, str], whom: Union[Member, str]) -> None: + async def love(self, ctx: commands.Context, who: Union[Member, str], whom: Union[Member, str] = None) -> None: """ Tells you how much the two love each other. @@ -45,7 +45,10 @@ class LoveCalculator(Cog): If you want to use multiple words for one argument, you must include quotes. .love "Zes Vappa" "morning coffee" """ - def normalize(arg: Union[Member, str]) -> str: + if whom is None: + whom = ctx.author + + def normalize(arg: Union[Member, str]) -> Coroutine: if isinstance(arg, Member): # If we are given a member, return name#discrim without any extra changes arg = str(arg) -- cgit v1.2.3 From 3d30a1ff9103fc59bd7fcc0ec8b1e7304beb08d4 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Fri, 5 Feb 2021 09:27:25 +0530 Subject: Abrupt response, so make the bot type --- bot/exts/evergreen/cheatsheet.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/cheatsheet.py b/bot/exts/evergreen/cheatsheet.py index f650e3b0..b3ee0b94 100644 --- a/bot/exts/evergreen/cheatsheet.py +++ b/bot/exts/evergreen/cheatsheet.py @@ -88,19 +88,20 @@ class CheatSheet(commands.Cog): ): return - async with self.bot.http_session.get( - URL.format(search=quote_plus(" ".join(search_terms))) - ) as response: - result = ANSI_RE.sub("", await response.text()).translate(ESCAPE_TT) - - is_embed, description = self.result_fmt( - URL.format(search=quote_plus(" ".join(search_terms))), - result - ) - if is_embed: - await ctx.send(embed=description) - else: - await ctx.send(content=description) + async with ctx.typing(): + async with self.bot.http_session.get( + URL.format(search=quote_plus(" ".join(search_terms))) + ) as response: + result = ANSI_RE.sub("", await response.text()).translate(ESCAPE_TT) + + is_embed, description = self.result_fmt( + URL.format(search=quote_plus(" ".join(search_terms))), + result + ) + if is_embed: + await ctx.send(embed=description) + else: + await ctx.send(content=description) def setup(bot: commands.Bot) -> None: -- cgit v1.2.3 From f6cccfe73321173d24667321b41f2e2b05f29aac Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Fri, 5 Feb 2021 09:28:28 +0530 Subject: Move repeated code to a single variable --- bot/exts/evergreen/cheatsheet.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/cheatsheet.py b/bot/exts/evergreen/cheatsheet.py index b3ee0b94..acd77e59 100644 --- a/bot/exts/evergreen/cheatsheet.py +++ b/bot/exts/evergreen/cheatsheet.py @@ -89,13 +89,15 @@ class CheatSheet(commands.Cog): return async with ctx.typing(): + search_string = quote_plus(" ".join(search_terms)) + async with self.bot.http_session.get( - URL.format(search=quote_plus(" ".join(search_terms))) + URL.format(search=search_string) ) as response: result = ANSI_RE.sub("", await response.text()).translate(ESCAPE_TT) is_embed, description = self.result_fmt( - URL.format(search=quote_plus(" ".join(search_terms))), + URL.format(search=search_string), result ) if is_embed: -- cgit v1.2.3 From 95950b93f5e01819921f9bc32a1613bdf1ddd13b Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Fri, 5 Feb 2021 09:30:10 +0530 Subject: Use brackets instead of / for multi line strings --- bot/exts/evergreen/cheatsheet.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/cheatsheet.py b/bot/exts/evergreen/cheatsheet.py index acd77e59..dd44c68e 100644 --- a/bot/exts/evergreen/cheatsheet.py +++ b/bot/exts/evergreen/cheatsheet.py @@ -58,14 +58,14 @@ class CheatSheet(commands.Cog): body_space = min(1986 - len(url), 1000) if len(body_text) > body_space: - description = f"**Result Of cht.sh**\n" \ - f"```python\n{body_text[:body_space]}\n" \ - f"... (truncated - too many lines)```\n" \ - f"Full results: {url} " + description = (f"**Result Of cht.sh**\n" + f"```python\n{body_text[:body_space]}\n" + f"... (truncated - too many lines)```\n" + f"Full results: {url} ") else: - description = f"**Result Of cht.sh**\n" \ - f"```python\n{body_text}```\n" \ - f"{url}" + description = (f"**Result Of cht.sh**\n" + f"```python\n{body_text}```\n" + f"{url}") return False, description @commands.command( -- cgit v1.2.3 From 23c0b2f9464b993c8f2fd33dc2941bef8b0a9851 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Fri, 5 Feb 2021 09:31:09 +0530 Subject: Fix indentation --- bot/exts/evergreen/cheatsheet.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/cheatsheet.py b/bot/exts/evergreen/cheatsheet.py index dd44c68e..97485365 100644 --- a/bot/exts/evergreen/cheatsheet.py +++ b/bot/exts/evergreen/cheatsheet.py @@ -59,13 +59,13 @@ class CheatSheet(commands.Cog): if len(body_text) > body_space: description = (f"**Result Of cht.sh**\n" - f"```python\n{body_text[:body_space]}\n" - f"... (truncated - too many lines)```\n" - f"Full results: {url} ") + f"```python\n{body_text[:body_space]}\n" + f"... (truncated - too many lines)```\n" + f"Full results: {url} ") else: description = (f"**Result Of cht.sh**\n" - f"```python\n{body_text}```\n" - f"{url}") + f"```python\n{body_text}```\n" + f"{url}") return False, description @commands.command( @@ -83,8 +83,8 @@ class CheatSheet(commands.Cog): --> .cht read json """ if not ( - ctx.channel.category.id == Categories.help_in_use - or ctx.channel.id in WHITELISTED_CHANNELS + ctx.channel.category.id == Categories.help_in_use + or ctx.channel.id in WHITELISTED_CHANNELS ): return -- cgit v1.2.3 From 370535b80690f89544840dc3967bfa7c59e6e667 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Sat, 6 Feb 2021 08:43:07 +0530 Subject: Improve grammar and update docstrings, add try..except block while sending DMs --- bot/exts/valentines/be_my_valentine.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'bot') diff --git a/bot/exts/valentines/be_my_valentine.py b/bot/exts/valentines/be_my_valentine.py index 41959409..26966804 100644 --- a/bot/exts/valentines/be_my_valentine.py +++ b/bot/exts/valentines/be_my_valentine.py @@ -73,7 +73,7 @@ class BeMyValentine(commands.Cog): self, ctx: commands.Context, user: discord.Member, *, valentine_type: str = None ) -> None: """ - Send a valentine to user, if specified, or to a random user with the lovefest role. + Send a valentine to a specified user with the lovefest role. syntax: .bemyvalentine [user] [p/poem/c/compliment/or you can type your own valentine message] (optional) @@ -89,7 +89,7 @@ class BeMyValentine(commands.Cog): return if Lovefest.role_id not in [role.id for role in user.roles]: - message = f"You cannot send a valentine to {user} as he/she does not have the lovefest role!" + message = f"You cannot send a valentine to {user} as they do not have the lovefest role!" await ctx.send(message) return @@ -115,7 +115,7 @@ class BeMyValentine(commands.Cog): self, ctx: commands.Context, user: discord.Member, *, valentine_type: str = None ) -> None: """ - Send an anonymous Valentine via DM to to a user, if specified, or to a random with the lovefest role. + Send an anonymous Valentine via DM to to a specified user with the lovefest role. syntax : .bemyvalentine secret [user] [p/poem/c/compliment/or you can type your own valentine message] (optional) @@ -125,14 +125,17 @@ class BeMyValentine(commands.Cog): Iceman in DM making you anonymous) """ if Lovefest.role_id not in [role.id for role in user.roles]: - message = f"You cannot send a valentine to {user} as he/she does not have the lovefest role!" + message = f"You cannot send a valentine to {user} as they do not have the lovefest role!" await ctx.message.delete() - return await ctx.author.send(message) + try: + await ctx.author.send(message) + except discord.Forbidden: + await ctx.send(message) if user == ctx.author: # Well a user cant valentine himself/herself. await ctx.message.delete() - return await ctx.author.send('Come on dude, you cant send a valentine to yourself :expressionless:') + await ctx.send('Come on dude, you cant send a valentine to yourself :expressionless:') emoji_1, emoji_2 = self.random_emoji() valentine, title = self.valentine_check(valentine_type) -- cgit v1.2.3 From a1ba7e857ecfae6382afc6f7fd479a246d953d36 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Sat, 6 Feb 2021 09:09:25 +0530 Subject: Slight modifications to functionality of bemyvalentine secret and its messages --- bot/exts/valentines/be_my_valentine.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'bot') diff --git a/bot/exts/valentines/be_my_valentine.py b/bot/exts/valentines/be_my_valentine.py index 26966804..d5668738 100644 --- a/bot/exts/valentines/be_my_valentine.py +++ b/bot/exts/valentines/be_my_valentine.py @@ -95,7 +95,7 @@ class BeMyValentine(commands.Cog): if user == ctx.author: # Well a user can't valentine himself/herself. - await ctx.send("Come on dude, you can't send a valentine to yourself :expressionless:") + await ctx.send("Come on, you can't send a valentine to yourself :expressionless:") return emoji_1, emoji_2 = self.random_emoji() @@ -109,7 +109,7 @@ class BeMyValentine(commands.Cog): ) await channel.send(user.mention, embed=embed) - @commands.cooldown(1, 1800, BucketType.user) + # @commands.cooldown(1, 1800, BucketType.user) @send_valentine.command(name='secret') async def anonymous( self, ctx: commands.Context, user: discord.Member, *, valentine_type: str = None @@ -131,11 +131,12 @@ class BeMyValentine(commands.Cog): await ctx.author.send(message) except discord.Forbidden: await ctx.send(message) + return if user == ctx.author: # Well a user cant valentine himself/herself. - await ctx.message.delete() - await ctx.send('Come on dude, you cant send a valentine to yourself :expressionless:') + await ctx.send('Come on, you cant send a valentine to yourself :expressionless:') + return emoji_1, emoji_2 = self.random_emoji() valentine, title = self.valentine_check(valentine_type) -- cgit v1.2.3 From 4d8e0c205aaa4a8e47486cccbeee383b5d899191 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Sat, 6 Feb 2021 09:09:51 +0530 Subject: Remove debug code --- bot/exts/valentines/be_my_valentine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/valentines/be_my_valentine.py b/bot/exts/valentines/be_my_valentine.py index d5668738..9ffa8769 100644 --- a/bot/exts/valentines/be_my_valentine.py +++ b/bot/exts/valentines/be_my_valentine.py @@ -109,7 +109,7 @@ class BeMyValentine(commands.Cog): ) await channel.send(user.mention, embed=embed) - # @commands.cooldown(1, 1800, BucketType.user) + @commands.cooldown(1, 1800, BucketType.user) @send_valentine.command(name='secret') async def anonymous( self, ctx: commands.Context, user: discord.Member, *, valentine_type: str = None -- cgit v1.2.3 From 24342ed41fea4079f464954fcaf873edcedabb07 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Sat, 6 Feb 2021 09:11:38 +0530 Subject: Small grammar fix --- bot/exts/valentines/be_my_valentine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/valentines/be_my_valentine.py b/bot/exts/valentines/be_my_valentine.py index 9ffa8769..d79b28e8 100644 --- a/bot/exts/valentines/be_my_valentine.py +++ b/bot/exts/valentines/be_my_valentine.py @@ -135,7 +135,7 @@ class BeMyValentine(commands.Cog): if user == ctx.author: # Well a user cant valentine himself/herself. - await ctx.send('Come on, you cant send a valentine to yourself :expressionless:') + await ctx.send('Come on, you can\'t send a valentine to yourself :expressionless:') return emoji_1, emoji_2 = self.random_emoji() -- cgit v1.2.3 From 0073e85b0adce4de6246a2e1013e3d84808de481 Mon Sep 17 00:00:00 2001 From: Hassan Abouelela <47495861+HassanAbouelela@users.noreply.github.com> Date: Sun, 7 Feb 2021 00:39:09 +0300 Subject: Overhauls In Channel Check Upgrades in channel check to support categories, and in the case of overrides, roles too. Signed-off-by: Hassan Abouelela <47495861+HassanAbouelela@users.noreply.github.com> --- bot/__main__.py | 5 +-- bot/utils/decorators.py | 110 +++++++++++++++++++++++++++--------------------- 2 files changed, 63 insertions(+), 52 deletions(-) (limited to 'bot') diff --git a/bot/__main__.py b/bot/__main__.py index e9b14a53..c6e5fa57 100644 --- a/bot/__main__.py +++ b/bot/__main__.py @@ -6,10 +6,9 @@ from sentry_sdk.integrations.redis import RedisIntegration from bot.bot import bot from bot.constants import Client, GIT_SHA, STAFF_ROLES, WHITELISTED_CHANNELS -from bot.utils.decorators import in_channel_check +from bot.utils.decorators import whitelist_check from bot.utils.extensions import walk_extensions - sentry_logging = LoggingIntegration( level=logging.DEBUG, event_level=logging.WARNING @@ -26,7 +25,7 @@ sentry_sdk.init( log = logging.getLogger(__name__) -bot.add_check(in_channel_check(*WHITELISTED_CHANNELS, bypass_roles=STAFF_ROLES)) +bot.add_check(whitelist_check(channels=WHITELISTED_CHANNELS, roles=STAFF_ROLES)) for ext in walk_extensions(): bot.load_extension(ext) diff --git a/bot/utils/decorators.py b/bot/utils/decorators.py index 9cdaad3f..66b30b97 100644 --- a/bot/utils/decorators.py +++ b/bot/utils/decorators.py @@ -13,6 +13,7 @@ from discord.ext.commands import CheckFailure, Command, Context from bot.constants import ERROR_REPLIES, Month from bot.utils import human_months, resolve_current_month +from bot.utils.checks import in_whitelist_check ONE_DAY = 24 * 60 * 60 @@ -186,82 +187,93 @@ def without_role(*role_ids: int) -> t.Callable: return commands.check(predicate) -def in_channel_check(*channels: int, bypass_roles: t.Container[int] = None) -> t.Callable[[Context], bool]: +def whitelist_check(**default_kwargs: t.Container[int]) -> t.Callable[[Context], bool]: """ - Checks that the message is in a whitelisted channel or optionally has a bypass role. + Checks if a message is sent in a whitelisted context. - If `in_channel_override` is present, check if it contains channels - and use them in place of the global whitelist. + All arguments from `in_whitelist_check` are supported, with the exception of "fail_silently". + If `whitelist_override` is present, it is added to the global whitelist. """ def predicate(ctx: Context) -> bool: + # Skip DM invocations if not ctx.guild: log.debug(f"{ctx.author} tried to use the '{ctx.command.name}' command from a DM.") return True - if ctx.channel.id in channels: - log.debug( - f"{ctx.author} tried to call the '{ctx.command.name}' command " - f"and the command was used in a whitelisted channel." - ) - return True - if bypass_roles and any(r.id in bypass_roles for r in ctx.author.roles): - log.debug( - f"{ctx.author} called the '{ctx.command.name}' command and " - f"had a role to bypass the in_channel check." - ) - return True + kwargs = default_kwargs.copy() - if hasattr(ctx.command.callback, "in_channel_override"): - override = ctx.command.callback.in_channel_override - if override is None: + # Update kwargs based on override + if hasattr(ctx.command.callback, "override"): + # Remove default kwargs if reset is True + if ctx.command.callback.override_reset: + kwargs = {} log.debug( - f"{ctx.author} called the '{ctx.command.name}' command " - f"and the command was whitelisted to bypass the in_channel check." + f"{ctx.author} called the '{ctx.command.name}' command and " + f"overrode default checks." ) - return True - else: - if ctx.channel.id in override: - log.debug( - f"{ctx.author} tried to call the '{ctx.command.name}' command " - f"and the command was used in an overridden whitelisted channel." - ) - return True - log.debug( - f"{ctx.author} tried to call the '{ctx.command.name}' command. " - f"The overridden in_channel check failed." - ) - channels_str = ', '.join(f"<#{c_id}>" for c_id in override) - raise InChannelCheckFailure( - f"Sorry, but you may only use this command within {channels_str}." - ) + # Merge overwrites and defaults + for arg in ctx.command.callback.override: + default_value = kwargs.get(arg) + new_value = ctx.command.callback.override[arg] + + # Skip values that don't need merging, or can't be merged + if default_value is None or isinstance(arg, int): + kwargs[arg] = new_value + + # Merge containers + elif isinstance(default_value, t.Container): + if isinstance(new_value, t.Container): + kwargs[arg] = (*default_value, *new_value) + else: + kwargs[arg] = new_value + + log.debug( + f"Updated default check arguments for '{ctx.command.name}' " + f"invoked by {ctx.author}." + ) + + log.trace(f"Calling whitelist check for {ctx.author} for command {ctx.command.name}.") + result = in_whitelist_check(ctx, fail_silently=True, **kwargs) + + # Return if check passed + if result: + log.debug( + f"{ctx.author} tried to call the '{ctx.command.name}' command " + f"and the command was used in an overridden context." + ) + return result log.debug( f"{ctx.author} tried to call the '{ctx.command.name}' command. " - f"The in_channel check failed." - ) - - channels_str = ', '.join(f"<#{c_id}>" for c_id in channels) - raise InChannelCheckFailure( - f"Sorry, but you may only use this command within {channels_str}." + f"The whitelist check failed." ) - return predicate + # Raise error if the check did not pass + channels = kwargs.get("channels") + if channels: + channels_str = ', '.join(f"<#{c_id}>" for c_id in channels) + message = f"Sorry, but you may only use this command within {channels_str}." + else: + message = "Sorry, but you may not use this command." + raise InChannelCheckFailure(message) -in_channel = commands.check(in_channel_check) + return predicate -def override_in_channel(channels: t.Tuple[int] = None) -> t.Callable: +def whitelist_override(bypass_defaults: bool = False, **kwargs: t.Container[int]) -> t.Callable: """ - Set command callback attribute for detection in `in_channel_check`. + Override global whitelist context, with the kwargs specified. - Override global whitelist if channels are specified. + All arguments from `in_whitelist_check` are supported, with the exception of `fail_silently`. + Set `bypass_defaults` to True if you want to completely bypass global checks. This decorator has to go before (below) below the `command` decorator. """ def inner(func: t.Callable) -> t.Callable: - func.in_channel_override = channels + func.override = kwargs + func.override_reset = bypass_defaults return func return inner -- cgit v1.2.3 From 9e714107d3ebe6b5f17a9705cdb69aafd7e0a07d Mon Sep 17 00:00:00 2001 From: Hassan Abouelela <47495861+HassanAbouelela@users.noreply.github.com> Date: Sun, 7 Feb 2021 00:42:19 +0300 Subject: Switches To Whitelist Check Switches all instances of override_in_channel to whitelist override. Signed-off-by: Hassan Abouelela <47495861+HassanAbouelela@users.noreply.github.com> --- bot/exts/christmas/advent_of_code/_cog.py | 20 ++++++++++---------- bot/exts/evergreen/conversationstarters.py | 4 ++-- bot/exts/halloween/hacktoberstats.py | 8 ++++---- 3 files changed, 16 insertions(+), 16 deletions(-) (limited to 'bot') diff --git a/bot/exts/christmas/advent_of_code/_cog.py b/bot/exts/christmas/advent_of_code/_cog.py index c3b87f96..466edd48 100644 --- a/bot/exts/christmas/advent_of_code/_cog.py +++ b/bot/exts/christmas/advent_of_code/_cog.py @@ -11,7 +11,7 @@ from bot.constants import ( AdventOfCode as AocConfig, Channels, Colours, Emojis, Month, Roles, WHITELISTED_CHANNELS, ) from bot.exts.christmas.advent_of_code import _helpers -from bot.utils.decorators import InChannelCheckFailure, in_month, override_in_channel, with_role +from bot.utils.decorators import InChannelCheckFailure, in_month, whitelist_override, with_role log = logging.getLogger(__name__) @@ -50,7 +50,7 @@ class AdventOfCode(commands.Cog): self.status_task.add_done_callback(_helpers.background_task_callback) @commands.group(name="adventofcode", aliases=("aoc",)) - @override_in_channel(AOC_WHITELIST) + @whitelist_override(channels=AOC_WHITELIST) async def adventofcode_group(self, ctx: commands.Context) -> None: """All of the Advent of Code commands.""" if not ctx.invoked_subcommand: @@ -61,7 +61,7 @@ class AdventOfCode(commands.Cog): aliases=("sub", "notifications", "notify", "notifs"), brief="Notifications for new days" ) - @override_in_channel(AOC_WHITELIST) + @whitelist_override(channels=AOC_WHITELIST) async def aoc_subscribe(self, ctx: commands.Context) -> None: """Assign the role for notifications about new days being ready.""" current_year = datetime.now().year @@ -82,7 +82,7 @@ class AdventOfCode(commands.Cog): @in_month(Month.DECEMBER) @adventofcode_group.command(name="unsubscribe", aliases=("unsub",), brief="Notifications for new days") - @override_in_channel(AOC_WHITELIST) + @whitelist_override(channels=AOC_WHITELIST) async def aoc_unsubscribe(self, ctx: commands.Context) -> None: """Remove the role for notifications about new days being ready.""" role = ctx.guild.get_role(AocConfig.role_id) @@ -94,7 +94,7 @@ class AdventOfCode(commands.Cog): await ctx.send("Hey, you don't even get any notifications about new Advent of Code tasks currently anyway.") @adventofcode_group.command(name="countdown", aliases=("count", "c"), brief="Return time left until next day") - @override_in_channel(AOC_WHITELIST) + @whitelist_override(channels=AOC_WHITELIST) async def aoc_countdown(self, ctx: commands.Context) -> None: """Return time left until next day.""" if not _helpers.is_in_advent(): @@ -123,13 +123,13 @@ class AdventOfCode(commands.Cog): await ctx.send(f"There are {hours} hours and {minutes} minutes left until day {tomorrow.day}.") @adventofcode_group.command(name="about", aliases=("ab", "info"), brief="Learn about Advent of Code") - @override_in_channel(AOC_WHITELIST) + @whitelist_override(channels=AOC_WHITELIST) async def about_aoc(self, ctx: commands.Context) -> None: """Respond with an explanation of all things Advent of Code.""" await ctx.send("", embed=self.cached_about_aoc) @adventofcode_group.command(name="join", aliases=("j",), brief="Learn how to join the leaderboard (via DM)") - @override_in_channel(AOC_WHITELIST) + @whitelist_override(channels=AOC_WHITELIST) async def join_leaderboard(self, ctx: commands.Context) -> None: """DM the user the information for joining the Python Discord leaderboard.""" current_year = datetime.now().year @@ -178,7 +178,7 @@ class AdventOfCode(commands.Cog): aliases=("board", "lb"), brief="Get a snapshot of the PyDis private AoC leaderboard", ) - @override_in_channel(AOC_WHITELIST_RESTRICTED) + @whitelist_override(channels=AOC_WHITELIST_RESTRICTED) async def aoc_leaderboard(self, ctx: commands.Context) -> None: """Get the current top scorers of the Python Discord Leaderboard.""" async with ctx.typing(): @@ -203,7 +203,7 @@ class AdventOfCode(commands.Cog): aliases=("globalboard", "gb"), brief="Get a link to the global leaderboard", ) - @override_in_channel(AOC_WHITELIST_RESTRICTED) + @whitelist_override(channels=AOC_WHITELIST_RESTRICTED) async def aoc_global_leaderboard(self, ctx: commands.Context) -> None: """Get a link to the global Advent of Code leaderboard.""" url = self.global_leaderboard_url @@ -219,7 +219,7 @@ class AdventOfCode(commands.Cog): aliases=("dailystats", "ds"), brief="Get daily statistics for the Python Discord leaderboard" ) - @override_in_channel(AOC_WHITELIST_RESTRICTED) + @whitelist_override(channels=AOC_WHITELIST_RESTRICTED) async def private_leaderboard_daily_stats(self, ctx: commands.Context) -> None: """Send an embed with daily completion statistics for the Python Discord leaderboard.""" try: diff --git a/bot/exts/evergreen/conversationstarters.py b/bot/exts/evergreen/conversationstarters.py index 576b8d76..e7058961 100644 --- a/bot/exts/evergreen/conversationstarters.py +++ b/bot/exts/evergreen/conversationstarters.py @@ -5,7 +5,7 @@ from discord import Color, Embed from discord.ext import commands from bot.constants import WHITELISTED_CHANNELS -from bot.utils.decorators import override_in_channel +from bot.utils.decorators import whitelist_override from bot.utils.randomization import RandomCycle SUGGESTION_FORM = 'https://forms.gle/zw6kkJqv8U43Nfjg9' @@ -38,7 +38,7 @@ class ConvoStarters(commands.Cog): self.bot = bot @commands.command() - @override_in_channel(ALL_ALLOWED_CHANNELS) + @whitelist_override(channels=ALL_ALLOWED_CHANNELS) async def topic(self, ctx: commands.Context) -> None: """ Responds with a random topic to start a conversation. diff --git a/bot/exts/halloween/hacktoberstats.py b/bot/exts/halloween/hacktoberstats.py index a1c55922..d9fc0e8a 100644 --- a/bot/exts/halloween/hacktoberstats.py +++ b/bot/exts/halloween/hacktoberstats.py @@ -11,7 +11,7 @@ from async_rediscache import RedisCache from discord.ext import commands from bot.constants import Channels, Month, NEGATIVE_REPLIES, Tokens, WHITELISTED_CHANNELS -from bot.utils.decorators import in_month, override_in_channel +from bot.utils.decorators import in_month, whitelist_override log = logging.getLogger(__name__) @@ -44,7 +44,7 @@ class HacktoberStats(commands.Cog): @in_month(Month.SEPTEMBER, Month.OCTOBER, Month.NOVEMBER) @commands.group(name="hacktoberstats", aliases=("hackstats",), invoke_without_command=True) - @override_in_channel(HACKTOBER_WHITELIST) + @whitelist_override(channels=HACKTOBER_WHITELIST) async def hacktoberstats_group(self, ctx: commands.Context, github_username: str = None) -> None: """ Display an embed for a user's Hacktoberfest contributions. @@ -72,7 +72,7 @@ class HacktoberStats(commands.Cog): @in_month(Month.SEPTEMBER, Month.OCTOBER, Month.NOVEMBER) @hacktoberstats_group.command(name="link") - @override_in_channel(HACKTOBER_WHITELIST) + @whitelist_override(channels=HACKTOBER_WHITELIST) async def link_user(self, ctx: commands.Context, github_username: str = None) -> None: """ Link the invoking user's Github github_username to their Discord ID. @@ -96,7 +96,7 @@ class HacktoberStats(commands.Cog): @in_month(Month.SEPTEMBER, Month.OCTOBER, Month.NOVEMBER) @hacktoberstats_group.command(name="unlink") - @override_in_channel(HACKTOBER_WHITELIST) + @whitelist_override(channels=HACKTOBER_WHITELIST) async def unlink_user(self, ctx: commands.Context) -> None: """Remove the invoking user's account link from the log.""" author_id, author_mention = self._author_mention_from_context(ctx) -- cgit v1.2.3 From ba439921a2164613ea7809cc006c621500bd727e Mon Sep 17 00:00:00 2001 From: Hassan Abouelela <47495861+HassanAbouelela@users.noreply.github.com> Date: Sun, 7 Feb 2021 09:42:24 +0300 Subject: Adds Whitelist Check To Cheat Sheet Signed-off-by: Hassan Abouelela <47495861+HassanAbouelela@users.noreply.github.com> --- bot/exts/evergreen/cheatsheet.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/cheatsheet.py b/bot/exts/evergreen/cheatsheet.py index 97485365..8e61f63e 100644 --- a/bot/exts/evergreen/cheatsheet.py +++ b/bot/exts/evergreen/cheatsheet.py @@ -8,8 +8,8 @@ from discord.ext import commands from discord.ext.commands import BucketType, Context from bot import constants -from bot.constants import Categories, Channels, Colours, ERROR_REPLIES, Roles, WHITELISTED_CHANNELS -from bot.utils.decorators import with_role +from bot.constants import Categories, Channels, Colours, ERROR_REPLIES +from bot.utils.decorators import whitelist_override ERROR_MESSAGE = f""" Unknown cheat sheet. Please try to reformulate your query. @@ -73,7 +73,7 @@ class CheatSheet(commands.Cog): aliases=("cht.sh", "cheatsheet", "cheat-sheet", "cht"), ) @commands.cooldown(1, 10, BucketType.user) - @with_role(Roles.everyone_role) + @whitelist_override(categories=[Categories.help_in_use]) async def cheat_sheet(self, ctx: Context, *search_terms: str) -> None: """ Search cheat.sh. @@ -82,12 +82,6 @@ class CheatSheet(commands.Cog): Usage: --> .cht read json """ - if not ( - ctx.channel.category.id == Categories.help_in_use - or ctx.channel.id in WHITELISTED_CHANNELS - ): - return - async with ctx.typing(): search_string = quote_plus(" ".join(search_terms)) -- cgit v1.2.3 From 73f11e22deda8bc25a03c75f3b7f380dd7f67f4e Mon Sep 17 00:00:00 2001 From: Hassan Abouelela <47495861+HassanAbouelela@users.noreply.github.com> Date: Sun, 7 Feb 2021 10:09:06 +0300 Subject: Adds Category Channels To Error Message Adds the channels within categories to the failure message of the command whitelist check. Signed-off-by: Hassan Abouelela <47495861+HassanAbouelela@users.noreply.github.com> --- bot/utils/decorators.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/utils/decorators.py b/bot/utils/decorators.py index 66b30b97..c12a15ff 100644 --- a/bot/utils/decorators.py +++ b/bot/utils/decorators.py @@ -250,7 +250,18 @@ def whitelist_check(**default_kwargs: t.Container[int]) -> t.Callable[[Context], ) # Raise error if the check did not pass - channels = kwargs.get("channels") + channels = set(kwargs.get("channels") or {}) + categories = kwargs.get("categories") + + # Add all whitelisted category channels + if categories: + for category_id in categories: + category = ctx.guild.get_channel(category_id) + if category is None: + continue + + [channels.add(channel.id) for channel in category.text_channels] + if channels: channels_str = ', '.join(f"<#{c_id}>" for c_id in channels) message = f"Sorry, but you may only use this command within {channels_str}." -- cgit v1.2.3 From 3242cc6c1dba0a0ecf3b5c0cdf5b90a4784dbfd1 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Mon, 8 Feb 2021 05:51:14 +0530 Subject: Add curl User Agent Headers --- bot/exts/evergreen/cheatsheet.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/cheatsheet.py b/bot/exts/evergreen/cheatsheet.py index 97485365..f6dce995 100644 --- a/bot/exts/evergreen/cheatsheet.py +++ b/bot/exts/evergreen/cheatsheet.py @@ -26,6 +26,7 @@ If the problem persists send a message in <#{Channels.dev_contrib}> URL = 'https://cheat.sh/python/{search}' ESCAPE_TT = str.maketrans({"`": "\\`"}) ANSI_RE = re.compile(r"\x1b\[.*?m") +HEADERS = {'User-Agent': 'curl/7.68.0'} class CheatSheet(commands.Cog): @@ -92,7 +93,7 @@ class CheatSheet(commands.Cog): search_string = quote_plus(" ".join(search_terms)) async with self.bot.http_session.get( - URL.format(search=search_string) + URL.format(search=search_string), headers=HEADERS ) as response: result = ANSI_RE.sub("", await response.text()).translate(ESCAPE_TT) -- cgit v1.2.3 From 8321add8d6a55132c96a620da2aac5c4bc44c284 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Mon, 8 Feb 2021 06:59:24 +0530 Subject: Use emojis library to do the check instead of checking len() == 1 since some emojis are made of len() > 1 --- Pipfile | 1 + Pipfile.lock | 55 ++++++++++++++++++++++---------------- bot/exts/evergreen/connect_four.py | 9 ++++--- 3 files changed, 39 insertions(+), 26 deletions(-) (limited to 'bot') diff --git a/Pipfile b/Pipfile index c382902f..e7e01a31 100644 --- a/Pipfile +++ b/Pipfile @@ -14,6 +14,7 @@ sentry-sdk = "~=0.19" PyYAML = "~=5.3.1" "discord.py" = {extras = ["voice"], version = "~=1.5.1"} async-rediscache = {extras = ["fakeredis"], version = "~=0.1.4"} +emojis = "~=0.6.0" [dev-packages] flake8 = "~=3.8" diff --git a/Pipfile.lock b/Pipfile.lock index be6f9574..cca89cf9 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "9be419062bd9db364ac9dddfcd50aef9c932384b45850363e482591fe7d12403" + "sha256": "b4aaaacbab13179145e36d7b86c736db512286f6cce8e513cc30c48d68fe3810" }, "pipfile-spec": 6, "requires": { @@ -119,6 +119,7 @@ "sha256:6bc25fc545a6b3d57b5f8618e59fc13d3a3a68431e8ca5fd4c13241cd70d0009", "sha256:798caa2a2384b1cbe8a2a139d80734c9db54f9cc155c99d7cc92441a23871c03", "sha256:7c6b1dece89874d9541fc974917b631406233ea0440d0bdfbb8e03bf39a49b3b", + "sha256:7ef7d4ced6b325e92eb4d3502946c78c5367bc416398d387b39591532536734e", "sha256:840793c68105fe031f34d6a086eaea153a0cd5c491cde82a74b420edd0a2b909", "sha256:8d6603078baf4e11edc4168a514c5ce5b3ba6e3e9c374298cb88437957960a53", "sha256:9cc46bc107224ff5b6d04369e7c595acb700c3613ad7bcf2e2012f62ece80c35", @@ -160,6 +161,14 @@ "index": "pypi", "version": "==1.5.1" }, + "emojis": { + "hashes": [ + "sha256:7da34c8a78ae262fd68cef9e2c78a3c1feb59784489eeea0f54ba1d4b7111c7c", + "sha256:bf605d1f1a27a81cd37fe82eb65781c904467f569295a541c33710b97e4225ec" + ], + "index": "pypi", + "version": "==0.6.0" + }, "fakeredis": { "hashes": [ "sha256:01cb47d2286825a171fb49c0e445b1fa9307087e07cbb3d027ea10dbff108b6a", @@ -229,11 +238,11 @@ }, "idna": { "hashes": [ - "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6", - "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0" + "sha256:5205d03e7bcbb919cc9c19885f9920d622ca52448306f2377daede5cf3faac16", + "sha256:c5b02147e01ea9920e6b0a3f1f7bb833612d507592c837a6c49552768f4054e1" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.10" + "markers": "python_version >= '3.4'", + "version": "==3.1" }, "multidict": { "hashes": [ @@ -436,11 +445,11 @@ }, "urllib3": { "hashes": [ - "sha256:19188f96923873c92ccb987120ec4acaa12f0461fa9ce5d3d0772bc965a39e08", - "sha256:d8ff90d979214d7b4f8ce956e80f4028fc6860e4431f731ea4a8c08f23f99473" + "sha256:1b465e494e3e0d8939b50680403e3aedaa2bc434b7d5af64dfd3c958d7f5ae80", + "sha256:de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", - "version": "==1.26.2" + "version": "==1.26.3" }, "yarl": { "hashes": [ @@ -514,11 +523,11 @@ }, "flake8-annotations": { "hashes": [ - "sha256:0bcebb0792f1f96d617ded674dca7bf64181870bfe5dace353a1483551f8e5f1", - "sha256:bebd11a850f6987a943ce8cdff4159767e0f5f89b3c88aca64680c2175ee02df" + "sha256:3a377140556aecf11fa9f3bb18c10db01f5ea56dc79a730e2ec9b4f1f49e2055", + "sha256:e17947a48a5b9f632fe0c72682fc797c385e451048e7dfb20139f448a074cb3e" ], "index": "pypi", - "version": "==2.4.1" + "version": "==2.5.0" }, "flake8-bugbear": { "hashes": [ @@ -576,11 +585,11 @@ }, "identify": { "hashes": [ - "sha256:943cd299ac7f5715fcb3f684e2fc1594c1e0f22a90d15398e5888143bd4144b5", - "sha256:cc86e6a9a390879dcc2976cef169dd9cc48843ed70b7380f321d1b118163c60e" + "sha256:70b638cf4743f33042bebb3b51e25261a0a10e80f978739f17e7fd4837664a66", + "sha256:9dfb63a2e871b807e3ba62f029813552a24b5289504f5b071dea9b041aee9fe4" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.5.10" + "version": "==1.5.13" }, "mccabe": { "hashes": [ @@ -606,11 +615,11 @@ }, "pre-commit": { "hashes": [ - "sha256:6c86d977d00ddc8a60d68eec19f51ef212d9462937acf3ea37c7adec32284ac0", - "sha256:ee784c11953e6d8badb97d19bc46b997a3a9eded849881ec587accd8608d74a4" + "sha256:16212d1fde2bed88159287da88ff03796863854b04dc9f838a55979325a3d20e", + "sha256:399baf78f13f4de82a29b649afd74bef2c4e28eb4f021661fc7f29246e8c7a3a" ], "index": "pypi", - "version": "==2.9.3" + "version": "==2.10.1" }, "pycodestyle": { "hashes": [ @@ -665,10 +674,10 @@ }, "snowballstemmer": { "hashes": [ - "sha256:209f257d7533fdb3cb73bdbd24f436239ca3b2fa67d56f6ff88e86be08cc5ef0", - "sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52" + "sha256:b51b447bea85f9968c13b650126a888aabd4cb4463fca868ec596826325dedc2", + "sha256:e997baa4f2e9139951b6f4c631bad912dfd3c792467e2f03d7239464af90e914" ], - "version": "==2.0.0" + "version": "==2.1.0" }, "toml": { "hashes": [ @@ -680,11 +689,11 @@ }, "virtualenv": { "hashes": [ - "sha256:54b05fc737ea9c9ee9f8340f579e5da5b09fb64fd010ab5757eb90268616907c", - "sha256:b7a8ec323ee02fb2312f098b6b4c9de99559b462775bc8fe3627a73706603c1b" + "sha256:147b43894e51dd6bba882cf9c282447f780e2251cd35172403745fc381a0a80d", + "sha256:2be72df684b74df0ea47679a7df93fd0e04e72520022c57b479d8f881485dbe3" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==20.2.2" + "version": "==20.4.2" } } } diff --git a/bot/exts/evergreen/connect_four.py b/bot/exts/evergreen/connect_four.py index bf604e2a..02e876f4 100644 --- a/bot/exts/evergreen/connect_four.py +++ b/bot/exts/evergreen/connect_four.py @@ -4,6 +4,7 @@ import typing from functools import partial import discord +import emojis from discord.ext import commands NUMBERS = [ @@ -342,11 +343,13 @@ class ConnectFour(commands.Cog): return any(player in (game.player1, game.player2) for game in self.games) @staticmethod - def check_emojis(e1: EMOJI_CHECK, e2: EMOJI_CHECK) -> typing.Tuple[bool, typing.Optional[str]]: + def check_emojis( + e1: EMOJI_CHECK, e2: EMOJI_CHECK + ) -> typing.Tuple[bool, typing.Optional[str]]: """Validate the emojis, the user put.""" - if isinstance(e1, str) and len(e1) > 1: + if isinstance(e1, str) and emojis.count(e1) != 1: return False, e1 - if isinstance(e2, str) and len(e2) > 1: + if isinstance(e2, str) and emojis.count(e2) != 1: return False, e2 return True, None -- cgit v1.2.3 From af1d11067daf1304c3c166202c13d8373da9e9b7 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Mon, 8 Feb 2021 14:08:54 +0530 Subject: Add comment explaining why we need to pass curl as user agent --- bot/exts/evergreen/cheatsheet.py | 1 + 1 file changed, 1 insertion(+) (limited to 'bot') diff --git a/bot/exts/evergreen/cheatsheet.py b/bot/exts/evergreen/cheatsheet.py index f6dce995..a64ddd69 100644 --- a/bot/exts/evergreen/cheatsheet.py +++ b/bot/exts/evergreen/cheatsheet.py @@ -26,6 +26,7 @@ If the problem persists send a message in <#{Channels.dev_contrib}> URL = 'https://cheat.sh/python/{search}' ESCAPE_TT = str.maketrans({"`": "\\`"}) ANSI_RE = re.compile(r"\x1b\[.*?m") +# We need to pass headers as curl otherwise it would default to aiohttp which would return raw html. HEADERS = {'User-Agent': 'curl/7.68.0'} -- cgit v1.2.3 From 2f032a71beadd6c9613b89d525004c98a4cf6ab9 Mon Sep 17 00:00:00 2001 From: Matteo Bertucci Date: Tue, 9 Feb 2021 11:41:28 +0100 Subject: Add location mocks to the wolfram cog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously the server IP address could be leaked using some query such as “what is the weather here?” or simply “what’s my ip?”. This aims to fix it by using mock locations. --- bot/exts/evergreen/wolfram.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/wolfram.py b/bot/exts/evergreen/wolfram.py index 898e8d2a..d3b4df5c 100644 --- a/bot/exts/evergreen/wolfram.py +++ b/bot/exts/evergreen/wolfram.py @@ -108,7 +108,10 @@ async def get_pod_pages(ctx: Context, bot: commands.Bot, query: str) -> Optional "input": query, "appid": APPID, "output": DEFAULT_OUTPUT_FORMAT, - "format": "image,plaintext" + "format": "image,plaintext", + "location": "the moon", + "latlong": "0.0,0.0", + "ip": "1.1.1.1" }) request_url = QUERY.format(request="query", data=url_str) -- cgit v1.2.3 From 87c4066eb016dace5d48d87fba83ce6424408878 Mon Sep 17 00:00:00 2001 From: Matteo Bertucci Date: Tue, 9 Feb 2021 12:22:26 +0100 Subject: Apply mock locations to every subcommands --- bot/exts/evergreen/wolfram.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'bot') diff --git a/bot/exts/evergreen/wolfram.py b/bot/exts/evergreen/wolfram.py index d3b4df5c..437d9e1a 100644 --- a/bot/exts/evergreen/wolfram.py +++ b/bot/exts/evergreen/wolfram.py @@ -171,6 +171,9 @@ class Wolfram(Cog): url_str = parse.urlencode({ "i": query, "appid": APPID, + "location": "the moon", + "latlong": "0.0,0.0", + "ip": "1.1.1.1" }) query = QUERY.format(request="simple", data=url_str) @@ -251,6 +254,9 @@ class Wolfram(Cog): url_str = parse.urlencode({ "i": query, "appid": APPID, + "location": "the moon", + "latlong": "0.0,0.0", + "ip": "1.1.1.1" }) query = QUERY.format(request="result", data=url_str) -- cgit v1.2.3 From 4c6d87c48bc44235a511f9266f986c219ac93f7e Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 13 Feb 2021 15:44:27 +0000 Subject: Raise user input error to reset cd --- bot/exts/valentines/be_my_valentine.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'bot') diff --git a/bot/exts/valentines/be_my_valentine.py b/bot/exts/valentines/be_my_valentine.py index d79b28e8..aac38edb 100644 --- a/bot/exts/valentines/be_my_valentine.py +++ b/bot/exts/valentines/be_my_valentine.py @@ -86,17 +86,17 @@ class BeMyValentine(commands.Cog): # This command should only be used in the server msg = "You are supposed to use this command in the server." await ctx.send(msg) - return + raise commands.UserInputError if Lovefest.role_id not in [role.id for role in user.roles]: message = f"You cannot send a valentine to {user} as they do not have the lovefest role!" await ctx.send(message) - return + raise commands.UserInputError if user == ctx.author: # Well a user can't valentine himself/herself. await ctx.send("Come on, you can't send a valentine to yourself :expressionless:") - return + raise commands.UserInputError emoji_1, emoji_2 = self.random_emoji() channel = self.bot.get_channel(Channels.community_bot_commands) @@ -131,12 +131,12 @@ class BeMyValentine(commands.Cog): await ctx.author.send(message) except discord.Forbidden: await ctx.send(message) - return + raise commands.UserInputError if user == ctx.author: # Well a user cant valentine himself/herself. await ctx.send('Come on, you can\'t send a valentine to yourself :expressionless:') - return + raise commands.UserInputError emoji_1, emoji_2 = self.random_emoji() valentine, title = self.valentine_check(valentine_type) @@ -151,6 +151,7 @@ class BeMyValentine(commands.Cog): await ctx.message.delete() except discord.Forbidden: await ctx.send(f"{user} has DMs disabled, so I couldn't send the message. Sorry!") + raise commands.UserInputError else: await ctx.author.send(f"Your message has been sent to {user}") -- cgit v1.2.3 From 8bc6f497d01d6b848ba868f4ac662100cdee48d3 Mon Sep 17 00:00:00 2001 From: MrKomodoDragon Date: Sat, 13 Feb 2021 11:03:14 -0800 Subject: Added description and url to embed of xkcd command --- bot/exts/evergreen/xkcd.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'bot') diff --git a/bot/exts/evergreen/xkcd.py b/bot/exts/evergreen/xkcd.py index d3224bfe..43f05864 100644 --- a/bot/exts/evergreen/xkcd.py +++ b/bot/exts/evergreen/xkcd.py @@ -69,6 +69,8 @@ class XKCD(Cog): return embed.title = f"XKCD comic #{info['num']}" + embed.description = info['alt'] + embed.url = f"{BASE_URL}/{comic}" if info["img"][-3:] in ("jpg", "png", "gif"): embed.set_image(url=info["img"]) -- cgit v1.2.3 From 7343af2b3a3cd0d0333a16de0557435ba21ba7ce Mon Sep 17 00:00:00 2001 From: MrKomodoDragon Date: Sat, 13 Feb 2021 11:34:37 -0800 Subject: FIxed error in which link would 404 if user did .xkcd latest --- Pipfile.lock | 132 ++++++++++++++++++++++----------------------- bot/exts/evergreen/xkcd.py | 2 +- 2 files changed, 67 insertions(+), 67 deletions(-) (limited to 'bot') diff --git a/Pipfile.lock b/Pipfile.lock index be6f9574..bd894ffa 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -103,44 +103,45 @@ }, "cffi": { "hashes": [ - "sha256:00a1ba5e2e95684448de9b89888ccd02c98d512064b4cb987d48f4b40aa0421e", - "sha256:00e28066507bfc3fe865a31f325c8391a1ac2916219340f87dfad602c3e48e5d", - "sha256:045d792900a75e8b1e1b0ab6787dd733a8190ffcf80e8c8ceb2fb10a29ff238a", - "sha256:0638c3ae1a0edfb77c6765d487fee624d2b1ee1bdfeffc1f0b58c64d149e7eec", - "sha256:105abaf8a6075dc96c1fe5ae7aae073f4696f2905fde6aeada4c9d2926752362", - "sha256:155136b51fd733fa94e1c2ea5211dcd4c8879869008fc811648f16541bf99668", - "sha256:1a465cbe98a7fd391d47dce4b8f7e5b921e6cd805ef421d04f5f66ba8f06086c", - "sha256:1d2c4994f515e5b485fd6d3a73d05526aa0fcf248eb135996b088d25dfa1865b", - "sha256:2c24d61263f511551f740d1a065eb0212db1dbbbbd241db758f5244281590c06", - "sha256:51a8b381b16ddd370178a65360ebe15fbc1c71cf6f584613a7ea08bfad946698", - "sha256:594234691ac0e9b770aee9fcdb8fa02c22e43e5c619456efd0d6c2bf276f3eb2", - "sha256:5cf4be6c304ad0b6602f5c4e90e2f59b47653ac1ed9c662ed379fe48a8f26b0c", - "sha256:64081b3f8f6f3c3de6191ec89d7dc6c86a8a43911f7ecb422c60e90c70be41c7", - "sha256:6bc25fc545a6b3d57b5f8618e59fc13d3a3a68431e8ca5fd4c13241cd70d0009", - "sha256:798caa2a2384b1cbe8a2a139d80734c9db54f9cc155c99d7cc92441a23871c03", - "sha256:7c6b1dece89874d9541fc974917b631406233ea0440d0bdfbb8e03bf39a49b3b", - "sha256:840793c68105fe031f34d6a086eaea153a0cd5c491cde82a74b420edd0a2b909", - "sha256:8d6603078baf4e11edc4168a514c5ce5b3ba6e3e9c374298cb88437957960a53", - "sha256:9cc46bc107224ff5b6d04369e7c595acb700c3613ad7bcf2e2012f62ece80c35", - "sha256:9f7a31251289b2ab6d4012f6e83e58bc3b96bd151f5b5262467f4bb6b34a7c26", - "sha256:9ffb888f19d54a4d4dfd4b3f29bc2c16aa4972f1c2ab9c4ab09b8ab8685b9c2b", - "sha256:a5ed8c05548b54b998b9498753fb9cadbfd92ee88e884641377d8a8b291bcc01", - "sha256:a7711edca4dcef1a75257b50a2fbfe92a65187c47dab5a0f1b9b332c5919a3fb", - "sha256:af5c59122a011049aad5dd87424b8e65a80e4a6477419c0c1015f73fb5ea0293", - "sha256:b18e0a9ef57d2b41f5c68beefa32317d286c3d6ac0484efd10d6e07491bb95dd", - "sha256:b4e248d1087abf9f4c10f3c398896c87ce82a9856494a7155823eb45a892395d", - "sha256:ba4e9e0ae13fc41c6b23299545e5ef73055213e466bd107953e4a013a5ddd7e3", - "sha256:c6332685306b6417a91b1ff9fae889b3ba65c2292d64bd9245c093b1b284809d", - "sha256:d5ff0621c88ce83a28a10d2ce719b2ee85635e85c515f12bac99a95306da4b2e", - "sha256:d9efd8b7a3ef378dd61a1e77367f1924375befc2eba06168b6ebfa903a5e59ca", - "sha256:df5169c4396adc04f9b0a05f13c074df878b6052430e03f50e68adf3a57aa28d", - "sha256:ebb253464a5d0482b191274f1c8bf00e33f7e0b9c66405fbffc61ed2c839c775", - "sha256:ec80dc47f54e6e9a78181ce05feb71a0353854cc26999db963695f950b5fb375", - "sha256:f032b34669220030f905152045dfa27741ce1a6db3324a5bc0b96b6c7420c87b", - "sha256:f60567825f791c6f8a592f3c6e3bd93dd2934e3f9dac189308426bd76b00ef3b", - "sha256:f803eaa94c2fcda012c047e62bc7a51b0bdabda1cad7a92a522694ea2d76e49f" - ], - "version": "==1.14.4" + "sha256:005a36f41773e148deac64b08f233873a4d0c18b053d37da83f6af4d9087b813", + "sha256:0857f0ae312d855239a55c81ef453ee8fd24136eaba8e87a2eceba644c0d4c06", + "sha256:1071534bbbf8cbb31b498d5d9db0f274f2f7a865adca4ae429e147ba40f73dea", + "sha256:158d0d15119b4b7ff6b926536763dc0714313aa59e320ddf787502c70c4d4bee", + "sha256:1f436816fc868b098b0d63b8920de7d208c90a67212546d02f84fe78a9c26396", + "sha256:2894f2df484ff56d717bead0a5c2abb6b9d2bf26d6960c4604d5c48bbc30ee73", + "sha256:29314480e958fd8aab22e4a58b355b629c59bf5f2ac2492b61e3dc06d8c7a315", + "sha256:34eff4b97f3d982fb93e2831e6750127d1355a923ebaeeb565407b3d2f8d41a1", + "sha256:35f27e6eb43380fa080dccf676dece30bef72e4a67617ffda586641cd4508d49", + "sha256:3d3dd4c9e559eb172ecf00a2a7517e97d1e96de2a5e610bd9b68cea3925b4892", + "sha256:43e0b9d9e2c9e5d152946b9c5fe062c151614b262fda2e7b201204de0b99e482", + "sha256:48e1c69bbacfc3d932221851b39d49e81567a4d4aac3b21258d9c24578280058", + "sha256:51182f8927c5af975fece87b1b369f722c570fe169f9880764b1ee3bca8347b5", + "sha256:58e3f59d583d413809d60779492342801d6e82fefb89c86a38e040c16883be53", + "sha256:5de7970188bb46b7bf9858eb6890aad302577a5f6f75091fd7cdd3ef13ef3045", + "sha256:65fa59693c62cf06e45ddbb822165394a288edce9e276647f0046e1ec26920f3", + "sha256:69e395c24fc60aad6bb4fa7e583698ea6cc684648e1ffb7fe85e3c1ca131a7d5", + "sha256:6c97d7350133666fbb5cf4abdc1178c812cb205dc6f41d174a7b0f18fb93337e", + "sha256:6e4714cc64f474e4d6e37cfff31a814b509a35cb17de4fb1999907575684479c", + "sha256:72d8d3ef52c208ee1c7b2e341f7d71c6fd3157138abf1a95166e6165dd5d4369", + "sha256:8ae6299f6c68de06f136f1f9e69458eae58f1dacf10af5c17353eae03aa0d827", + "sha256:8b198cec6c72df5289c05b05b8b0969819783f9418e0409865dac47288d2a053", + "sha256:99cd03ae7988a93dd00bcd9d0b75e1f6c426063d6f03d2f90b89e29b25b82dfa", + "sha256:9cf8022fb8d07a97c178b02327b284521c7708d7c71a9c9c355c178ac4bbd3d4", + "sha256:9de2e279153a443c656f2defd67769e6d1e4163952b3c622dcea5b08a6405322", + "sha256:9e93e79c2551ff263400e1e4be085a1210e12073a31c2011dbbda14bda0c6132", + "sha256:9ff227395193126d82e60319a673a037d5de84633f11279e336f9c0f189ecc62", + "sha256:a465da611f6fa124963b91bf432d960a555563efe4ed1cc403ba5077b15370aa", + "sha256:ad17025d226ee5beec591b52800c11680fca3df50b8b29fe51d882576e039ee0", + "sha256:afb29c1ba2e5a3736f1c301d9d0abe3ec8b86957d04ddfa9d7a6a42b9367e396", + "sha256:b85eb46a81787c50650f2392b9b4ef23e1f126313b9e0e9013b35c15e4288e2e", + "sha256:bb89f306e5da99f4d922728ddcd6f7fcebb3241fc40edebcb7284d7514741991", + "sha256:cbde590d4faaa07c72bf979734738f328d239913ba3e043b1e98fe9a39f8b2b6", + "sha256:cd2868886d547469123fadc46eac7ea5253ea7fcb139f12e1dfc2bbd406427d1", + "sha256:d42b11d692e11b6634f7613ad8df5d6d5f8875f5d48939520d351007b3c13406", + "sha256:f2d45f97ab6bb54753eab54fffe75aaf3de4ff2341c9daee1987ee1837636f1d", + "sha256:fd78e5fee591709f32ef6edb9a015b4aa1a5022598e36227500c8f4e02328d9c" + ], + "version": "==1.14.5" }, "chardet": { "hashes": [ @@ -229,11 +230,11 @@ }, "idna": { "hashes": [ - "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6", - "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0" + "sha256:5205d03e7bcbb919cc9c19885f9920d622ca52448306f2377daede5cf3faac16", + "sha256:c5b02147e01ea9920e6b0a3f1f7bb833612d507592c837a6c49552768f4054e1" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.10" + "markers": "python_version >= '3.4'", + "version": "==3.1" }, "multidict": { "hashes": [ @@ -405,11 +406,10 @@ }, "sentry-sdk": { "hashes": [ - "sha256:0a711ec952441c2ec89b8f5d226c33bc697914f46e876b44a4edd3e7864cf4d0", - "sha256:737a094e49a529dd0fdcaafa9e97cf7c3d5eb964bd229821d640bc77f3502b3f" + "sha256:3693cb47ba8d90c004ac002425770b32aaf0c83a846ec48e2d1364e7db1d072d" ], "index": "pypi", - "version": "==0.19.5" + "version": "==0.20.1" }, "six": { "hashes": [ @@ -428,19 +428,19 @@ }, "soupsieve": { "hashes": [ - "sha256:4bb21a6ee4707bf43b61230e80740e71bfe56e55d1f1f50924b087bb2975c851", - "sha256:6dc52924dc0bc710a5d16794e6b3480b2c7c08b07729505feab2b2c16661ff6e" + "sha256:407fa1e8eb3458d1b5614df51d9651a1180ea5fedf07feb46e45d7e25e6d6cdd", + "sha256:d3a5ea5b350423f47d07639f74475afedad48cf41c0ad7a82ca13a3928af34f6" ], "markers": "python_version >= '3.0'", - "version": "==2.1" + "version": "==2.2" }, "urllib3": { "hashes": [ - "sha256:19188f96923873c92ccb987120ec4acaa12f0461fa9ce5d3d0772bc965a39e08", - "sha256:d8ff90d979214d7b4f8ce956e80f4028fc6860e4431f731ea4a8c08f23f99473" + "sha256:1b465e494e3e0d8939b50680403e3aedaa2bc434b7d5af64dfd3c958d7f5ae80", + "sha256:de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", - "version": "==1.26.2" + "version": "==1.26.3" }, "yarl": { "hashes": [ @@ -514,11 +514,11 @@ }, "flake8-annotations": { "hashes": [ - "sha256:0bcebb0792f1f96d617ded674dca7bf64181870bfe5dace353a1483551f8e5f1", - "sha256:bebd11a850f6987a943ce8cdff4159767e0f5f89b3c88aca64680c2175ee02df" + "sha256:3a377140556aecf11fa9f3bb18c10db01f5ea56dc79a730e2ec9b4f1f49e2055", + "sha256:e17947a48a5b9f632fe0c72682fc797c385e451048e7dfb20139f448a074cb3e" ], "index": "pypi", - "version": "==2.4.1" + "version": "==2.5.0" }, "flake8-bugbear": { "hashes": [ @@ -576,11 +576,11 @@ }, "identify": { "hashes": [ - "sha256:943cd299ac7f5715fcb3f684e2fc1594c1e0f22a90d15398e5888143bd4144b5", - "sha256:cc86e6a9a390879dcc2976cef169dd9cc48843ed70b7380f321d1b118163c60e" + "sha256:70b638cf4743f33042bebb3b51e25261a0a10e80f978739f17e7fd4837664a66", + "sha256:9dfb63a2e871b807e3ba62f029813552a24b5289504f5b071dea9b041aee9fe4" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.5.10" + "version": "==1.5.13" }, "mccabe": { "hashes": [ @@ -606,11 +606,11 @@ }, "pre-commit": { "hashes": [ - "sha256:6c86d977d00ddc8a60d68eec19f51ef212d9462937acf3ea37c7adec32284ac0", - "sha256:ee784c11953e6d8badb97d19bc46b997a3a9eded849881ec587accd8608d74a4" + "sha256:16212d1fde2bed88159287da88ff03796863854b04dc9f838a55979325a3d20e", + "sha256:399baf78f13f4de82a29b649afd74bef2c4e28eb4f021661fc7f29246e8c7a3a" ], "index": "pypi", - "version": "==2.9.3" + "version": "==2.10.1" }, "pycodestyle": { "hashes": [ @@ -665,10 +665,10 @@ }, "snowballstemmer": { "hashes": [ - "sha256:209f257d7533fdb3cb73bdbd24f436239ca3b2fa67d56f6ff88e86be08cc5ef0", - "sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52" + "sha256:b51b447bea85f9968c13b650126a888aabd4cb4463fca868ec596826325dedc2", + "sha256:e997baa4f2e9139951b6f4c631bad912dfd3c792467e2f03d7239464af90e914" ], - "version": "==2.0.0" + "version": "==2.1.0" }, "toml": { "hashes": [ @@ -680,11 +680,11 @@ }, "virtualenv": { "hashes": [ - "sha256:54b05fc737ea9c9ee9f8340f579e5da5b09fb64fd010ab5757eb90268616907c", - "sha256:b7a8ec323ee02fb2312f098b6b4c9de99559b462775bc8fe3627a73706603c1b" + "sha256:147b43894e51dd6bba882cf9c282447f780e2251cd35172403745fc381a0a80d", + "sha256:2be72df684b74df0ea47679a7df93fd0e04e72520022c57b479d8f881485dbe3" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==20.2.2" + "version": "==20.4.2" } } } diff --git a/bot/exts/evergreen/xkcd.py b/bot/exts/evergreen/xkcd.py index 43f05864..1ff98ca2 100644 --- a/bot/exts/evergreen/xkcd.py +++ b/bot/exts/evergreen/xkcd.py @@ -70,7 +70,7 @@ class XKCD(Cog): embed.title = f"XKCD comic #{info['num']}" embed.description = info['alt'] - embed.url = f"{BASE_URL}/{comic}" + embed.url = f"{BASE_URL}/{info['num']}" if info["img"][-3:] in ("jpg", "png", "gif"): embed.set_image(url=info["img"]) -- cgit v1.2.3 From 2d33d53bf2c3a26e68abdcf2a2f91dac5bd495fc Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 13 Feb 2021 23:12:43 +0000 Subject: Output message in the same embed. --- bot/exts/valentines/be_my_valentine.py | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) (limited to 'bot') diff --git a/bot/exts/valentines/be_my_valentine.py b/bot/exts/valentines/be_my_valentine.py index aac38edb..fe52936b 100644 --- a/bot/exts/valentines/be_my_valentine.py +++ b/bot/exts/valentines/be_my_valentine.py @@ -84,19 +84,16 @@ class BeMyValentine(commands.Cog): """ if ctx.guild is None: # This command should only be used in the server - msg = "You are supposed to use this command in the server." - await ctx.send(msg) - raise commands.UserInputError + raise commands.UserInputError("You are supposed to use this command in the server.") if Lovefest.role_id not in [role.id for role in user.roles]: - message = f"You cannot send a valentine to {user} as they do not have the lovefest role!" - await ctx.send(message) - raise commands.UserInputError + raise commands.UserInputError( + f"You cannot send a valentine to {user} as they do not have the lovefest role!" + ) if user == ctx.author: # Well a user can't valentine himself/herself. - await ctx.send("Come on, you can't send a valentine to yourself :expressionless:") - raise commands.UserInputError + raise commands.UserInputError("Come on, you can't send a valentine to yourself :expressionless:") emoji_1, emoji_2 = self.random_emoji() channel = self.bot.get_channel(Channels.community_bot_commands) @@ -125,18 +122,14 @@ class BeMyValentine(commands.Cog): Iceman in DM making you anonymous) """ if Lovefest.role_id not in [role.id for role in user.roles]: - message = f"You cannot send a valentine to {user} as they do not have the lovefest role!" await ctx.message.delete() - try: - await ctx.author.send(message) - except discord.Forbidden: - await ctx.send(message) - raise commands.UserInputError + raise commands.UserInputError( + f"You cannot send a valentine to {user}> as they do not have the lovefest role!" + ) if user == ctx.author: # Well a user cant valentine himself/herself. - await ctx.send('Come on, you can\'t send a valentine to yourself :expressionless:') - raise commands.UserInputError + raise commands.UserInputError("Come on, you can't send a valentine to yourself :expressionless:") emoji_1, emoji_2 = self.random_emoji() valentine, title = self.valentine_check(valentine_type) @@ -146,12 +139,11 @@ class BeMyValentine(commands.Cog): description=f'{valentine} \n **{emoji_2}From anonymous{emoji_1}**', color=Colours.pink ) + await ctx.message.delete() try: await user.send(embed=embed) - await ctx.message.delete() except discord.Forbidden: - await ctx.send(f"{user} has DMs disabled, so I couldn't send the message. Sorry!") - raise commands.UserInputError + raise commands.UserInputError(f"{user} has DMs disabled, so I couldn't send the message. Sorry!") else: await ctx.author.send(f"Your message has been sent to {user}") -- cgit v1.2.3 From ab5e00d836a4c01c581a877c2dc992f3fa8d9243 Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 13 Feb 2021 23:16:48 +0000 Subject: Remove leftover > from testing. --- bot/exts/valentines/be_my_valentine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/valentines/be_my_valentine.py b/bot/exts/valentines/be_my_valentine.py index fe52936b..f3392bcb 100644 --- a/bot/exts/valentines/be_my_valentine.py +++ b/bot/exts/valentines/be_my_valentine.py @@ -124,7 +124,7 @@ class BeMyValentine(commands.Cog): if Lovefest.role_id not in [role.id for role in user.roles]: await ctx.message.delete() raise commands.UserInputError( - f"You cannot send a valentine to {user}> as they do not have the lovefest role!" + f"You cannot send a valentine to {user} as they do not have the lovefest role!" ) if user == ctx.author: -- cgit v1.2.3 From 7ba7149c688ba35d60934fdc68b92b82862065c7 Mon Sep 17 00:00:00 2001 From: MrKomodoDragon Date: Tue, 16 Feb 2021 09:10:57 -0800 Subject: Add .pyfacts command --- bot/exts/evergreen/pythonfacts.py | 23 +++++++++++++++++++++++ bot/resources/evergreen/python_facts.txt | 3 +++ 2 files changed, 26 insertions(+) create mode 100644 bot/exts/evergreen/pythonfacts.py create mode 100644 bot/resources/evergreen/python_facts.txt (limited to 'bot') diff --git a/bot/exts/evergreen/pythonfacts.py b/bot/exts/evergreen/pythonfacts.py new file mode 100644 index 00000000..ba792561 --- /dev/null +++ b/bot/exts/evergreen/pythonfacts.py @@ -0,0 +1,23 @@ +import random + +import discord +from discord.ext import commands +from discord.ext.commands.bot import Bot + + +class PythonFacts(commands.Cog): + """Gives a random fun fact about Python.""" + + def __init__(self, bot: Bot) -> None: + self.bot = bot + + @commands.command(name='pythonfact', aliases=['pyfact']) + async def get_python_fact(self, ctx: commands.Context) -> None: + """Gives a Random fun fact about Python.""" + with open('bot/resources/evergreen/python_facts.txt') as file: + await ctx.send(embed=discord.Embed(title='Python Facts', description=f'**{random.choice(list(file))}**')) + + +def setup(bot: commands.Bot) -> None: + """Adding the cog to the bot.""" + bot.add_cog(PythonFacts(bot)) diff --git a/bot/resources/evergreen/python_facts.txt b/bot/resources/evergreen/python_facts.txt new file mode 100644 index 00000000..d9e63a11 --- /dev/null +++ b/bot/resources/evergreen/python_facts.txt @@ -0,0 +1,3 @@ +Python was named after Monty Python, which Guido van Rossum likes. +If you type `import this` in the Python REPL, you'll get a poem about the philosophies about Python. (check it out by doing !zen in <#267659945086812160>) +If you type `import antigravity` in the Python REPL, you'll be directed to an [xkcd comic](https://xkcd.com/353/) about how easy Python is. -- cgit v1.2.3 From fdfa5c75b74a898512bfac6fa3ac14d452eae05d Mon Sep 17 00:00:00 2001 From: MrKomodoDragon Date: Tue, 16 Feb 2021 10:44:21 -0800 Subject: Remove unused import --- bot/exts/evergreen/pythonfacts.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/pythonfacts.py b/bot/exts/evergreen/pythonfacts.py index ba792561..b1c28d4b 100644 --- a/bot/exts/evergreen/pythonfacts.py +++ b/bot/exts/evergreen/pythonfacts.py @@ -2,13 +2,12 @@ import random import discord from discord.ext import commands -from discord.ext.commands.bot import Bot class PythonFacts(commands.Cog): """Gives a random fun fact about Python.""" - def __init__(self, bot: Bot) -> None: + def __init__(self, bot: commands.Bot) -> None: self.bot = bot @commands.command(name='pythonfact', aliases=['pyfact']) -- cgit v1.2.3 From 06d600f0fd927e566d23879638d10c6d66a63a21 Mon Sep 17 00:00:00 2001 From: MrKomodoDragon Date: Tue, 16 Feb 2021 10:48:13 -0800 Subject: Move loading of file outside of command --- bot/exts/evergreen/pythonfacts.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/pythonfacts.py b/bot/exts/evergreen/pythonfacts.py index b1c28d4b..c6592add 100644 --- a/bot/exts/evergreen/pythonfacts.py +++ b/bot/exts/evergreen/pythonfacts.py @@ -4,6 +4,10 @@ import discord from discord.ext import commands +with open('bot/resources/evergreen/python_facts.txt') as file: + FACTS = list(file) + + class PythonFacts(commands.Cog): """Gives a random fun fact about Python.""" @@ -13,8 +17,7 @@ class PythonFacts(commands.Cog): @commands.command(name='pythonfact', aliases=['pyfact']) async def get_python_fact(self, ctx: commands.Context) -> None: """Gives a Random fun fact about Python.""" - with open('bot/resources/evergreen/python_facts.txt') as file: - await ctx.send(embed=discord.Embed(title='Python Facts', description=f'**{random.choice(list(file))}**')) + await ctx.send(embed=discord.Embed(title='Python Facts', description=f'**{random.choice(FACTS)}**')) def setup(bot: commands.Bot) -> None: -- cgit v1.2.3 From 57aec016ac74465212744a9ec4173515dca98ba1 Mon Sep 17 00:00:00 2001 From: MrKomodoDragon <74436682+MrKomodoDragon@users.noreply.github.com> Date: Tue, 16 Feb 2021 17:57:51 -0800 Subject: Remove bold Co-authored-by: Shivansh-007 <69356296+Shivansh-007@users.noreply.github.com> --- bot/exts/evergreen/pythonfacts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/pythonfacts.py b/bot/exts/evergreen/pythonfacts.py index c6592add..fcb78168 100644 --- a/bot/exts/evergreen/pythonfacts.py +++ b/bot/exts/evergreen/pythonfacts.py @@ -17,7 +17,7 @@ class PythonFacts(commands.Cog): @commands.command(name='pythonfact', aliases=['pyfact']) async def get_python_fact(self, ctx: commands.Context) -> None: """Gives a Random fun fact about Python.""" - await ctx.send(embed=discord.Embed(title='Python Facts', description=f'**{random.choice(FACTS)}**')) + await ctx.send(embed=discord.Embed(title='Python Facts', description=random.choice(FACTS))) def setup(bot: commands.Bot) -> None: -- cgit v1.2.3 From a68e8f558cfee18bdb04c9e9a07cc9d293bd6c71 Mon Sep 17 00:00:00 2001 From: MrKomodoDragon <74436682+MrKomodoDragon@users.noreply.github.com> Date: Tue, 16 Feb 2021 17:58:31 -0800 Subject: Update docstring for Cog Co-authored-by: Shivansh-007 <69356296+Shivansh-007@users.noreply.github.com> --- bot/exts/evergreen/pythonfacts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/pythonfacts.py b/bot/exts/evergreen/pythonfacts.py index fcb78168..dbc38ef4 100644 --- a/bot/exts/evergreen/pythonfacts.py +++ b/bot/exts/evergreen/pythonfacts.py @@ -21,5 +21,5 @@ class PythonFacts(commands.Cog): def setup(bot: commands.Bot) -> None: - """Adding the cog to the bot.""" + """Load PythonFacts Cog.""" bot.add_cog(PythonFacts(bot)) -- cgit v1.2.3 From 6aae339f33ee471bafe9338db5046b774c6b4aad Mon Sep 17 00:00:00 2001 From: MrKomodoDragon <74436682+MrKomodoDragon@users.noreply.github.com> Date: Tue, 16 Feb 2021 18:03:31 -0800 Subject: Change Docstring for command Co-authored-by: Shivansh-007 <69356296+Shivansh-007@users.noreply.github.com> --- bot/exts/evergreen/pythonfacts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/pythonfacts.py b/bot/exts/evergreen/pythonfacts.py index dbc38ef4..c0cdf111 100644 --- a/bot/exts/evergreen/pythonfacts.py +++ b/bot/exts/evergreen/pythonfacts.py @@ -16,7 +16,7 @@ class PythonFacts(commands.Cog): @commands.command(name='pythonfact', aliases=['pyfact']) async def get_python_fact(self, ctx: commands.Context) -> None: - """Gives a Random fun fact about Python.""" + """Sends a Random fun fact about Python.""" await ctx.send(embed=discord.Embed(title='Python Facts', description=random.choice(FACTS))) -- cgit v1.2.3 From 5164ba4e367efbfe78f8dd2b08646fe6605a8b42 Mon Sep 17 00:00:00 2001 From: MrKomodoDragon Date: Tue, 16 Feb 2021 18:21:12 -0800 Subject: Add colors and move embed out of send statement; add more info about Monty Python for Fact 1 --- bot/exts/evergreen/pythonfacts.py | 7 +++++-- bot/resources/evergreen/python_facts.txt | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/pythonfacts.py b/bot/exts/evergreen/pythonfacts.py index c0cdf111..734782b8 100644 --- a/bot/exts/evergreen/pythonfacts.py +++ b/bot/exts/evergreen/pythonfacts.py @@ -7,9 +7,11 @@ from discord.ext import commands with open('bot/resources/evergreen/python_facts.txt') as file: FACTS = list(file) +COLORS = [0x4B8BBE, 0xFFD43B, ] + class PythonFacts(commands.Cog): - """Gives a random fun fact about Python.""" + """Sends a random fun fact about Python.""" def __init__(self, bot: commands.Bot) -> None: self.bot = bot @@ -17,7 +19,8 @@ class PythonFacts(commands.Cog): @commands.command(name='pythonfact', aliases=['pyfact']) async def get_python_fact(self, ctx: commands.Context) -> None: """Sends a Random fun fact about Python.""" - await ctx.send(embed=discord.Embed(title='Python Facts', description=random.choice(FACTS))) + embed = discord.Embed(title='Python Facts', description=random.choice(FACTS), colour=random.choice(COLORS)) + await ctx.send(embed=embed) def setup(bot: commands.Bot) -> None: diff --git a/bot/resources/evergreen/python_facts.txt b/bot/resources/evergreen/python_facts.txt index d9e63a11..0abd971b 100644 --- a/bot/resources/evergreen/python_facts.txt +++ b/bot/resources/evergreen/python_facts.txt @@ -1,3 +1,3 @@ -Python was named after Monty Python, which Guido van Rossum likes. +Python was named after Monty Python, a British Comedy Troupe, which Guido van Rossum likes. If you type `import this` in the Python REPL, you'll get a poem about the philosophies about Python. (check it out by doing !zen in <#267659945086812160>) If you type `import antigravity` in the Python REPL, you'll be directed to an [xkcd comic](https://xkcd.com/353/) about how easy Python is. -- cgit v1.2.3 From 7bc0ea474ed39dbddca3958bb90fc072f0d7aa1d Mon Sep 17 00:00:00 2001 From: Arez1337 <> Date: Sat, 20 Feb 2021 20:43:59 +0100 Subject: Removed the Question about the Nile and changed the IDs to matc the order again --- bot/resources/evergreen/trivia_quiz.json | 57 ++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 24 deletions(-) (limited to 'bot') diff --git a/bot/resources/evergreen/trivia_quiz.json b/bot/resources/evergreen/trivia_quiz.json index faa3bc3b..a4225eb1 100644 --- a/bot/resources/evergreen/trivia_quiz.json +++ b/bot/resources/evergreen/trivia_quiz.json @@ -2,36 +2,51 @@ "retro": [ { "id": 1, - "hints": ["It is not a mainline Mario Game, although the plumber is present.", "It is not a mainline Zelda Game, although Link is present."], + "hints": [ + "It is not a mainline Mario Game, although the plumber is present.", + "It is not a mainline Zelda Game, although Link is present." + ], "question": "What is the best selling game on the Nintendo GameCube?", "answer": "Super Smash Bros" }, { "id": 2, - "hints": ["It was released before the 90's.", "It was released after 1980."], + "hints": [ + "It was released before the 90's.", + "It was released after 1980." + ], "question": "What year was Tetris released?", "answer": "1984" }, { "id": 3, - "hints": ["The occupation was in construction", "He appeared as this kind of worker in 1981's Donkey Kong"], + "hints": [ + "The occupation was in construction", + "He appeared as this kind of worker in 1981's Donkey Kong" + ], "question": "What was Mario's original occupation?", "answer": "Carpenter" }, { "id": 4, - "hints": ["It was revealed in the Nintendo Character Guide in 1993.", "His last name has to do with eating Mario's enemies."], + "hints": [ + "It was revealed in the Nintendo Character Guide in 1993.", + "His last name has to do with eating Mario's enemies." + ], "question": "What is Yoshi's (from Mario Bros.) full name?", "answer": "Yoshisaur Munchakoopas" }, { "id": 5, - "hints": ["The game was released in 1990.", "It was released on the SNES."], + "hints": [ + "The game was released in 1990.", + "It was released on the SNES." + ], "question": "What was the first game Yoshi appeared in?", "answer": "Super Mario World" } ], - "general":[ + "general": [ { "id": 100, "question": "Name \"the land of a thousand lakes\"", @@ -114,7 +129,7 @@ "id": 113, "question": "What's the name of the tallest waterfall in the world.", "answer": "Angel Falls", - "info": "Angel Falls (Salto Ángel) in Venezuela is the highest waterfall in the world. The falls are 3230 feet in height, with an uninterrupted drop of 2647 feet. Angel Falls is located on a tributary of the Rio Caroni." + "info": "Angel Falls (Salto \u00c1ngel) in Venezuela is the highest waterfall in the world. The falls are 3230 feet in height, with an uninterrupted drop of 2647 feet. Angel Falls is located on a tributary of the Rio Caroni." }, { "id": 114, @@ -180,7 +195,7 @@ "id": 124, "question": "When did the Second World War end?", "answer": "1945", - "info": "World War 2 ended with the unconditional surrender of the Axis powers. On 8 May 1945, the Allies accepted Germany's surrender, about a week after Adolf Hitler had committed suicide. VE Day – Victory in Europe celebrates the end of the Second World War on 8 May 1945." + "info": "World War 2 ended with the unconditional surrender of the Axis powers. On 8 May 1945, the Allies accepted Germany's surrender, about a week after Adolf Hitler had committed suicide. VE Day \u2013 Victory in Europe celebrates the end of the Second World War on 8 May 1945." }, { "id": 125, @@ -190,72 +205,66 @@ }, { "id": 126, - "question": "What's the name of the largest river in the world?", - "answer": "Nile", - "info": "The Nile, which is about 6,650 km (4,130 mi) long, is an \"international\" river as its drainage basin covers eleven countries, namely, Tanzania, Uganda, Rwanda, Burundi, the Democratic Republic of the Congo, Kenya, Ethiopia, Eritrea, South Sudan, Republic of the Sudan and Egypt." - }, - { - "id": 127, "question": "Which is the smallest planet in the Solar System?", "answer": "Mercury", "info": "Mercury is the smallest planet in our solar system. It's just a little bigger than Earth's moon. It is the closest planet to the sun, but it's actually not the hottest. Venus is hotter." }, { - "id": 128, + "id": 127, "question": "What is the smallest country?", "answer": "Vatican City", "info": "With an area of 0.17 square miles (0.44 km2) and a population right around 1,000, Vatican City is the smallest country in the world, both in terms of size and population." }, { - "id": 129, + "id": 128, "question": "What's the name of the largest bird?", "answer": "Ostrich", "info": "The largest living bird, a member of the Struthioniformes, is the ostrich (Struthio camelus), from the plains of Africa and Arabia. A large male ostrich can reach a height of 2.8 metres (9.2 feet) and weigh over 156 kilograms (344 pounds)." }, { - "id": 130, + "id": 129, "question": "What does the acronym GPRS stand for?", "answer": "General Packet Radio Service", "info": "General Packet Radio Service (GPRS) is a packet-based mobile data service on the global system for mobile communications (GSM) of 3G and 2G cellular communication systems. It is a non-voice, high-speed and useful packet-switching technology intended for GSM networks." }, { - "id": 131, + "id": 130, "question": "In what country is the Ebro river located?", "answer": "Spain", "info": "The Ebro river is located in Spain. It is 930 kilometers long and it's the second longest river that ends on the Mediterranean Sea." }, { - "id": 132, + "id": 131, "question": "What year was the IBM PC model 5150 introduced into the market?", "answer": "1981", "info": "The IBM PC was introduced into the market in 1981. It used the Intel 8088, with a clock speed of 4.77 MHz, along with the MDA and CGA as a video card." }, { - "id": 133, + "id": 132, "question": "What's the world's largest urban area?", "answer": "Tokyo", "info": "Tokyo is the most populated city in the world, with a population of 37 million people. It is located in Japan." }, { - "id": 134, + "id": 133, "question": "How many planets are there in the Solar system?", "answer": "8", "info": "In the Solar system, there are 8 planets: Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus and Neptune. Pluto isn't considered a planet in the Solar System anymore." }, { - "id": 135, + "id": 134, "question": "What is the capital of Iraq?", "answer": "Baghdad", "info": "Baghdad is the capital of Iraq. It has a population of 7 million people." }, { - "id": 136, + "id": 135, "question": "The United Nations headquarters is located at which city?", "answer": "New York", "info": "The United Nations is headquartered in New York City in a complex designed by a board of architects led by Wallace Harrison and built by the architectural firm Harrison & Abramovitz. The complex has served as the official headquarters of the United Nations since its completion in 1951." }, { - "id": 137, + "id": 136, "question": "At what year did Christopher Columbus discover America?", "answer": "1492", "info": "The explorer Christopher Columbus made four trips across the Atlantic Ocean from Spain: in 1492, 1493, 1498 and 1502. He was determined to find a direct water route west from Europe to Asia, but he never did. Instead, he stumbled upon the Americas" -- cgit v1.2.3 From 8cdd0b337fadc7085638517af5e8a7474ea3271c Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Mon, 22 Feb 2021 20:40:10 +0530 Subject: Improve wikipedia command to send a snippet of wikipedia article and use pagination instead of asking user for input --- bot/exts/evergreen/wikipedia.py | 168 ++++++++++++++++++---------------------- 1 file changed, 76 insertions(+), 92 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/wikipedia.py b/bot/exts/evergreen/wikipedia.py index be36e2c4..0d100d90 100644 --- a/bot/exts/evergreen/wikipedia.py +++ b/bot/exts/evergreen/wikipedia.py @@ -1,114 +1,98 @@ -import asyncio -import datetime import logging +import re +from datetime import datetime +from enum import Enum +from html import unescape from typing import List, Optional -from aiohttp import client_exceptions -from discord import Color, Embed, Message +from discord import Color, Embed from discord.ext import commands -from bot.constants import Wikipedia +from bot.bot import Bot +from bot.utils import LinePaginator log = logging.getLogger(__name__) -SEARCH_API = "https://en.wikipedia.org/w/api.php?action=query&list=search&srsearch={search_term}&format=json" -WIKIPEDIA_URL = "https://en.wikipedia.org/wiki/{title}" +SEARCH_API = "https://en.wikipedia.org/w/api.php?action=query&list=search&prop=info&inprop=url&utf8=& \ + format=json&origin=*&srlimit={number_of_results}&srsearch={string}" +WIKI_THUMBNAIL = "https://upload.wikimedia.org/wikipedia/en/thumb/8/80/Wikipedia-logo-v2.svg" \ + "/330px-Wikipedia-logo-v2.svg.png" +WIKI_SNIPPET_REGEX = r'(|<[^>]*>)' +WIKI_SEARCH_RESULT = ( + "**[{name}]({url})**\n" + "{description}\n" +) -class WikipediaSearch(commands.Cog): - """Get info from wikipedia.""" +class WikipediaSearchErrors(Enum): + """Errors returned in wikipedia search function.""" - def __init__(self, bot: commands.Bot): - self.bot = bot - self.http_session = bot.http_session + no_results = "Sorry, we could not find a wikipedia article using that search term." + api_issue = "Whoops, the Wikipedia API is having some issues right now. Try again later." - @staticmethod - def formatted_wiki_url(index: int, title: str) -> str: - """Formating wikipedia link with index and title.""" - return f'`{index}` [{title}]({WIKIPEDIA_URL.format(title=title.replace(" ", "_"))})' - async def search_wikipedia(self, search_term: str) -> Optional[List[str]]: - """Search wikipedia and return the first 10 pages found.""" - pages = [] - async with self.http_session.get(SEARCH_API.format(search_term=search_term)) as response: - try: - data = await response.json() +class WikipediaSearch(commands.Cog): + """Get info from wikipedia.""" - search_results = data["query"]["search"] + def __init__(self, bot: Bot): + self.bot = bot - # Ignore pages with "may refer to" - for search_result in search_results: - log.info("trying to append titles") - if "may refer to" not in search_result["snippet"]: - pages.append(search_result["title"]) - except client_exceptions.ContentTypeError: - pages = None + async def wiki_request(self, ctx: commands.Context, search: str) -> Optional[List[str]]: + """Search wikipedia search string and return formatted first 10 pages found.""" + url = SEARCH_API.format(number_of_results=10, string=search) + async with self.bot.http_session.get(url=url) as resp: + if resp.status == 200: + raw_data = await resp.json() + number_of_results = raw_data['query']['searchinfo']['totalhits'] + + if number_of_results: + results = raw_data['query']['search'] + lines = [] + + for article in results: + formatting = { + 'name': article['title'], + 'description': unescape( + re.sub( + WIKI_SNIPPET_REGEX, '', article['snippet'] + ) + ), + 'url': f"https://en.wikipedia.org/?curid={article['pageid']}" + } + line = WIKI_SEARCH_RESULT.format(**formatting) + lines.append(line) + + return lines - log.info("Finished appending titles") - return pages + else: + await ctx.send( + WikipediaSearchErrors.no_results.value + ) + return None + else: + await ctx.send( + WikipediaSearchErrors.api_issue.value + ) + return None @commands.cooldown(1, 10, commands.BucketType.user) @commands.command(name="wikipedia", aliases=["wiki"]) async def wikipedia_search_command(self, ctx: commands.Context, *, search: str) -> None: - """Return list of results containing your search query from wikipedia.""" - titles = await self.search_wikipedia(search) - - def check(message: Message) -> bool: - return message.author.id == ctx.author.id and message.channel == ctx.channel - - if not titles: - await ctx.send("Sorry, we could not find a wikipedia article using that search term") - return - - async with ctx.typing(): - log.info("Finished appending titles to titles_no_underscore list") - - s_desc = "\n".join(self.formatted_wiki_url(index, title) for index, title in enumerate(titles, start=1)) - embed = Embed(colour=Color.blue(), title=f"Wikipedia results for `{search}`", description=s_desc) - embed.timestamp = datetime.datetime.utcnow() - await ctx.send(embed=embed) - embed = Embed(colour=Color.green(), description="Enter number to choose") - msg = await ctx.send(embed=embed) - titles_len = len(titles) # getting length of list - - for retry_count in range(1, Wikipedia.total_chance + 1): - retries_left = Wikipedia.total_chance - retry_count - if retry_count < Wikipedia.total_chance: - error_msg = f"You have `{retries_left}/{Wikipedia.total_chance}` chances left" - else: - error_msg = 'Please try again by using `.wiki` command' - try: - message = await ctx.bot.wait_for('message', timeout=60.0, check=check) - response_from_user = await self.bot.get_context(message) - - if response_from_user.command: - return - - response = int(message.content) - if response < 0: - await ctx.send(f"Sorry, but you can't give negative index, {error_msg}") - elif response == 0: - await ctx.send(f"Sorry, please give an integer between `1` to `{titles_len}`, {error_msg}") - else: - await ctx.send(WIKIPEDIA_URL.format(title=titles[response - 1].replace(" ", "_"))) - break - - except asyncio.TimeoutError: - embed = Embed(colour=Color.red(), description=f"Time's up {ctx.author.mention}") - await msg.edit(embed=embed) - break - - except ValueError: - await ctx.send(f"Sorry, but you cannot do that, I will only accept an positive integer, {error_msg}") - - except IndexError: - await ctx.send(f"Sorry, please give an integer between `1` to `{titles_len}`, {error_msg}") - - except Exception as e: - log.info(f"Caught exception {e}, breaking out of retry loop") - break - - -def setup(bot: commands.Bot) -> None: + """Sends paginated top 10 results of Wikipedia search..""" + contents = await self.wiki_request(ctx, search) + + if contents: + embed = Embed( + title="Wikipedia Search Results", + colour=Color.blurple() + ) + embed.set_thumbnail(url=WIKI_THUMBNAIL) + embed.timestamp = datetime.utcnow() + await LinePaginator.paginate( + contents, ctx, embed + ) + + +def setup(bot: Bot) -> None: """Wikipedia Cog load.""" bot.add_cog(WikipediaSearch(bot)) -- cgit v1.2.3 From 86dc294eb22f233ccd381529a8191d2285889784 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Mon, 22 Feb 2021 20:40:56 +0530 Subject: Goodbye Wikipedia Class, no need of you anymore --- bot/constants.py | 4 ---- 1 file changed, 4 deletions(-) (limited to 'bot') diff --git a/bot/constants.py b/bot/constants.py index bb538487..c31cd958 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -281,10 +281,6 @@ class RedisConfig(NamedTuple): use_fakeredis = environ.get("USE_FAKEREDIS", "false").lower() == "true" -class Wikipedia: - total_chance = 3 - - class Source: github = "https://github.com/python-discord/sir-lancebot" github_avatar_url = "https://avatars1.githubusercontent.com/u/9919" -- cgit v1.2.3 From 16476ab7b4d5efe36a9e101b382f7be24888dec5 Mon Sep 17 00:00:00 2001 From: MrKomodoDragon Date: Mon, 22 Feb 2021 11:13:01 -0800 Subject: Switch to itertools.cycle and add colors to constants.py --- bot/constants.py | 2 ++ bot/exts/evergreen/pythonfacts.py | 9 ++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'bot') diff --git a/bot/constants.py b/bot/constants.py index bb538487..3aec6ba3 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -156,6 +156,8 @@ class Colours: soft_orange = 0xf9cb54 soft_red = 0xcd6d6d yellow = 0xf9f586 + python_blue = 0x4B8BBE + python_yellow = 0xFFD43B class Emojis: diff --git a/bot/exts/evergreen/pythonfacts.py b/bot/exts/evergreen/pythonfacts.py index 734782b8..8e6d300b 100644 --- a/bot/exts/evergreen/pythonfacts.py +++ b/bot/exts/evergreen/pythonfacts.py @@ -1,13 +1,16 @@ -import random +import itertools import discord from discord.ext import commands +from bot.constants import Colours with open('bot/resources/evergreen/python_facts.txt') as file: FACTS = list(file) + FACT_CYCLE = itertools.cycle(FACTS) -COLORS = [0x4B8BBE, 0xFFD43B, ] +COLORS = [Colours.python_blue, Colours.python_yellow] +COLOR_CYCLE = itertools.cycle(COLORS) class PythonFacts(commands.Cog): @@ -19,7 +22,7 @@ class PythonFacts(commands.Cog): @commands.command(name='pythonfact', aliases=['pyfact']) async def get_python_fact(self, ctx: commands.Context) -> None: """Sends a Random fun fact about Python.""" - embed = discord.Embed(title='Python Facts', description=random.choice(FACTS), colour=random.choice(COLORS)) + embed = discord.Embed(title='Python Facts', description=next(FACT_CYCLE), colour=next(COLOR_CYCLE)) await ctx.send(embed=embed) -- cgit v1.2.3 From fa9e205338429def46b1c962138eda52c44ba824 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Tue, 23 Feb 2021 12:06:59 +0530 Subject: Add log.info() statement if the wikipedia api request status code is not 200 --- bot/exts/evergreen/wikipedia.py | 1 + 1 file changed, 1 insertion(+) (limited to 'bot') diff --git a/bot/exts/evergreen/wikipedia.py b/bot/exts/evergreen/wikipedia.py index 0d100d90..0b64136f 100644 --- a/bot/exts/evergreen/wikipedia.py +++ b/bot/exts/evergreen/wikipedia.py @@ -70,6 +70,7 @@ class WikipediaSearch(commands.Cog): ) return None else: + log.info(f"Unexpected response `{resp.status}` while searching wikipedia for `{search}`") await ctx.send( WikipediaSearchErrors.api_issue.value ) -- cgit v1.2.3 From 13dad6bf796a6009db4ff768795a3d45d044ff0e Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Tue, 23 Feb 2021 16:46:08 +0530 Subject: Fix pipfile conflicts, and add/use emojis from constants.py --- Pipfile.lock | 21 +++++++++++++++------ bot/constants.py | 5 ++++- bot/exts/evergreen/connect_four.py | 37 +++++++++---------------------------- 3 files changed, 28 insertions(+), 35 deletions(-) (limited to 'bot') diff --git a/Pipfile.lock b/Pipfile.lock index bd894ffa..ec801979 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "9be419062bd9db364ac9dddfcd50aef9c932384b45850363e482591fe7d12403" + "sha256": "b4aaaacbab13179145e36d7b86c736db512286f6cce8e513cc30c48d68fe3810" }, "pipfile-spec": 6, "requires": { @@ -161,6 +161,14 @@ "index": "pypi", "version": "==1.5.1" }, + "emojis": { + "hashes": [ + "sha256:7da34c8a78ae262fd68cef9e2c78a3c1feb59784489eeea0f54ba1d4b7111c7c", + "sha256:bf605d1f1a27a81cd37fe82eb65781c904467f569295a541c33710b97e4225ec" + ], + "index": "pypi", + "version": "==0.6.0" + }, "fakeredis": { "hashes": [ "sha256:01cb47d2286825a171fb49c0e445b1fa9307087e07cbb3d027ea10dbff108b6a", @@ -406,10 +414,11 @@ }, "sentry-sdk": { "hashes": [ - "sha256:3693cb47ba8d90c004ac002425770b32aaf0c83a846ec48e2d1364e7db1d072d" + "sha256:4ae8d1ced6c67f1c8ea51d82a16721c166c489b76876c9f2c202b8a50334b237", + "sha256:e75c8c58932bda8cd293ea8e4b242527129e1caaec91433d21b8b2f20fee030b" ], "index": "pypi", - "version": "==0.20.1" + "version": "==0.20.3" }, "six": { "hashes": [ @@ -576,11 +585,11 @@ }, "identify": { "hashes": [ - "sha256:70b638cf4743f33042bebb3b51e25261a0a10e80f978739f17e7fd4837664a66", - "sha256:9dfb63a2e871b807e3ba62f029813552a24b5289504f5b071dea9b041aee9fe4" + "sha256:de7129142a5c86d75a52b96f394d94d96d497881d2aaf8eafe320cdbe8ac4bcc", + "sha256:e0dae57c0397629ce13c289f6ddde0204edf518f557bfdb1e56474aa143e77c3" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.5.13" + "version": "==1.5.14" }, "mccabe": { "hashes": [ diff --git a/bot/constants.py b/bot/constants.py index bb538487..682ccf6f 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -165,6 +165,7 @@ class Emojis: envelope = "\U0001F4E8" trashcan = "<:trashcan:637136429717389331>" ok_hand = ":ok_hand:" + hand_raised = "\U0001f64b" dice_1 = "<:dice_1:755891608859443290>" dice_2 = "<:dice_2:755891608741740635>" @@ -179,7 +180,6 @@ class Emojis: pull_request_closed = "<:PRClosed:629695470519713818>" merge = "<:PRMerged:629695470570176522>" - # TicTacToe Emojis number_emojis = { 1: "\u0031\ufe0f\u20e3", 2: "\u0032\ufe0f\u20e3", @@ -191,8 +191,11 @@ class Emojis: 8: "\u0038\ufe0f\u20e3", 9: "\u0039\ufe0f\u20e3" } + confirmation = "\u2705" decline = "\u274c" + incident_unactioned = "<:incident_unactioned:719645583245180960>" + x = "\U0001f1fd" o = "\U0001f1f4" diff --git a/bot/exts/evergreen/connect_four.py b/bot/exts/evergreen/connect_four.py index 02e876f4..65458dbc 100644 --- a/bot/exts/evergreen/connect_four.py +++ b/bot/exts/evergreen/connect_four.py @@ -7,30 +7,11 @@ import discord import emojis from discord.ext import commands -NUMBERS = [ - ":one:", - ":two:", - ":three:", - ":four:", - ":five:", - ":six:", - ":seven:", - ":eight:", - ":nine:" -] -UNICODE_NUMBERS = [ - "\u0031\u20e3", - "\u0032\u20e3", - "\u0033\u20e3", - "\u0034\u20e3", - "\u0035\u20e3", - "\u0036\u20e3", - "\u0037\u20e3", - "\u0038\u20e3", - "\u0039\u20e3", -] -CROSS_EMOJI = "\u274e" -HAND_RAISED_EMOJI = "\U0001f64b" +from bot.constants import Emojis + +NUMBERS = list(Emojis.number_emojis.values()) +CROSS_EMOJI = Emojis.incident_unactioned + Coordinate = typing.Optional[typing.Tuple[int, int]] EMOJI_CHECK = typing.Union[discord.Emoji, str] @@ -57,7 +38,7 @@ class Game: self.grid = self.generate_board(size) self.grid_size = size - self.unicode_numbers = UNICODE_NUMBERS[:self.grid_size] + self.unicode_numbers = NUMBERS[:self.grid_size] self.message = None @@ -313,7 +294,7 @@ class ConnectFour(commands.Cog): if ( user.id not in (ctx.me.id, ctx.author.id) - and str(reaction.emoji) == HAND_RAISED_EMOJI + and str(reaction.emoji) == Emojis.hand_raised and reaction.message.id == announcement.id ): if self.already_playing(user): @@ -406,11 +387,11 @@ class ConnectFour(commands.Cog): announcement = await ctx.send( "**Connect Four**: A new game is about to start!\n" - f"Press {HAND_RAISED_EMOJI} to play against {ctx.author.mention}!\n" + f"Press {Emojis.hand_raised} to play against {ctx.author.mention}!\n" f"(Cancel the game with {CROSS_EMOJI}.)" ) self.waiting.append(ctx.author) - await announcement.add_reaction(HAND_RAISED_EMOJI) + await announcement.add_reaction(Emojis.hand_raised) await announcement.add_reaction(CROSS_EMOJI) try: -- cgit v1.2.3 From aef25cb560eb525305c583a8ff2834b503cb91d4 Mon Sep 17 00:00:00 2001 From: MrKomodoDragon Date: Tue, 23 Feb 2021 09:03:05 -0800 Subject: Remove unused variables --- bot/exts/evergreen/pythonfacts.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/pythonfacts.py b/bot/exts/evergreen/pythonfacts.py index 8e6d300b..11b258f9 100644 --- a/bot/exts/evergreen/pythonfacts.py +++ b/bot/exts/evergreen/pythonfacts.py @@ -6,11 +6,9 @@ from discord.ext import commands from bot.constants import Colours with open('bot/resources/evergreen/python_facts.txt') as file: - FACTS = list(file) - FACT_CYCLE = itertools.cycle(FACTS) + FACTS = itertools.cycle(list(file)) -COLORS = [Colours.python_blue, Colours.python_yellow] -COLOR_CYCLE = itertools.cycle(COLORS) +COLORS = itertools.cycle([Colours.python_blue, Colours.python_yellow]) class PythonFacts(commands.Cog): @@ -22,7 +20,7 @@ class PythonFacts(commands.Cog): @commands.command(name='pythonfact', aliases=['pyfact']) async def get_python_fact(self, ctx: commands.Context) -> None: """Sends a Random fun fact about Python.""" - embed = discord.Embed(title='Python Facts', description=next(FACT_CYCLE), colour=next(COLOR_CYCLE)) + embed = discord.Embed(title='Python Facts', description=next(FACTS), colour=next(COLORS)) await ctx.send(embed=embed) -- cgit v1.2.3 From b70a3fb551600fc34ea4d9e5111957149dceb1a2 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Wed, 24 Feb 2021 17:28:08 +0530 Subject: Make connect 4 and its sub command ai guild only --- bot/exts/evergreen/connect_four.py | 3 + bot/exts/evergreen/error_handler.py | 129 ------------------------------------ 2 files changed, 3 insertions(+), 129 deletions(-) delete mode 100644 bot/exts/evergreen/error_handler.py (limited to 'bot') diff --git a/bot/exts/evergreen/connect_four.py b/bot/exts/evergreen/connect_four.py index 65458dbc..7e3ec42b 100644 --- a/bot/exts/evergreen/connect_four.py +++ b/bot/exts/evergreen/connect_four.py @@ -6,6 +6,7 @@ from functools import partial import discord import emojis from discord.ext import commands +from discord.ext.commands import guild_only from bot.constants import Emojis @@ -358,6 +359,7 @@ class ConnectFour(commands.Cog): self.games.remove(game) raise + @guild_only() @commands.group( invoke_without_command=True, aliases=["4inarow", "connect4", "connectfour", "c4"], @@ -422,6 +424,7 @@ class ConnectFour(commands.Cog): await self._play_game(ctx, user, board_size, str(emoji1), str(emoji2)) + @guild_only() @connect_four.command(aliases=["bot", "computer", "cpu"]) async def ai( self, diff --git a/bot/exts/evergreen/error_handler.py b/bot/exts/evergreen/error_handler.py deleted file mode 100644 index 99af1519..00000000 --- a/bot/exts/evergreen/error_handler.py +++ /dev/null @@ -1,129 +0,0 @@ -import logging -import math -import random -from typing import Iterable, Union - -from discord import Embed, Message -from discord.ext import commands -from sentry_sdk import push_scope - -from bot.constants import Colours, ERROR_REPLIES, NEGATIVE_REPLIES -from bot.utils.decorators import InChannelCheckFailure, InMonthCheckFailure -from bot.utils.exceptions import UserNotPlayingError - -log = logging.getLogger(__name__) - - -class CommandErrorHandler(commands.Cog): - """A error handler for the PythonDiscord server.""" - - def __init__(self, bot: commands.Bot): - self.bot = bot - - @staticmethod - def revert_cooldown_counter(command: commands.Command, message: Message) -> None: - """Undoes the last cooldown counter for user-error cases.""" - if command._buckets.valid: - bucket = command._buckets.get_bucket(message) - bucket._tokens = min(bucket.rate, bucket._tokens + 1) - logging.debug("Cooldown counter reverted as the command was not used correctly.") - - @staticmethod - def error_embed(message: str, title: Union[Iterable, str] = ERROR_REPLIES) -> Embed: - """Build a basic embed with red colour and either a random error title or a title provided.""" - embed = Embed(colour=Colours.soft_red) - if isinstance(title, str): - embed.title = title - else: - embed.title = random.choice(title) - embed.description = message - return embed - - @commands.Cog.listener() - async def on_command_error(self, ctx: commands.Context, error: commands.CommandError) -> None: - """Activates when a command opens an error.""" - if getattr(error, 'handled', False): - logging.debug(f"Command {ctx.command} had its error already handled locally; ignoring.") - return - - error = getattr(error, 'original', error) - logging.debug( - f"Error Encountered: {type(error).__name__} - {str(error)}, " - f"Command: {ctx.command}, " - f"Author: {ctx.author}, " - f"Channel: {ctx.channel}" - ) - - if isinstance(error, commands.CommandNotFound): - return - - if isinstance(error, (InChannelCheckFailure, InMonthCheckFailure)): - await ctx.send(embed=self.error_embed(str(error), NEGATIVE_REPLIES), delete_after=7.5) - return - - if isinstance(error, commands.UserInputError): - self.revert_cooldown_counter(ctx.command, ctx.message) - embed = self.error_embed( - f"Your input was invalid: {error}\n\nUsage:\n```{ctx.prefix}{ctx.command} {ctx.command.signature}```" - ) - await ctx.send(embed=embed) - return - - if isinstance(error, commands.CommandOnCooldown): - mins, secs = divmod(math.ceil(error.retry_after), 60) - embed = self.error_embed( - f"This command is on cooldown:\nPlease retry in {mins} minutes {secs} seconds.", - NEGATIVE_REPLIES - ) - await ctx.send(embed=embed, delete_after=7.5) - return - - if isinstance(error, commands.DisabledCommand): - await ctx.send(embed=self.error_embed("This command has been disabled.", NEGATIVE_REPLIES)) - return - - if isinstance(error, commands.NoPrivateMessage): - await ctx.send(embed=self.error_embed("This command can only be used in the server.", NEGATIVE_REPLIES)) - return - - if isinstance(error, commands.BadArgument): - self.revert_cooldown_counter(ctx.command, ctx.message) - embed = self.error_embed( - "The argument you provided was invalid: " - f"{error}\n\nUsage:\n```{ctx.prefix}{ctx.command} {ctx.command.signature}```" - ) - await ctx.send(embed=embed) - return - - if isinstance(error, commands.CheckFailure): - await ctx.send(embed=self.error_embed("You are not authorized to use this command.", NEGATIVE_REPLIES)) - return - - if isinstance(error, UserNotPlayingError): - await ctx.send("Game not found.") - return - - with push_scope() as scope: - scope.user = { - "id": ctx.author.id, - "username": str(ctx.author) - } - - scope.set_tag("command", ctx.command.qualified_name) - scope.set_tag("message_id", ctx.message.id) - scope.set_tag("channel_id", ctx.channel.id) - - scope.set_extra("full_message", ctx.message.content) - - if ctx.guild is not None: - scope.set_extra( - "jump_to", - f"https://discordapp.com/channels/{ctx.guild.id}/{ctx.channel.id}/{ctx.message.id}" - ) - - log.exception(f"Unhandled command error: {str(error)}", exc_info=error) - - -def setup(bot: commands.Bot) -> None: - """Error handler Cog load.""" - bot.add_cog(CommandErrorHandler(bot)) -- cgit v1.2.3 From fadb1c4e13086d9ecf17629d98668364bd78bf54 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Wed, 24 Feb 2021 17:28:38 +0530 Subject: Mentioned community bot commands channel while sending embed for No Private Message error --- bot/exts/evergreen/error_handler.py | 133 ++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 bot/exts/evergreen/error_handler.py (limited to 'bot') diff --git a/bot/exts/evergreen/error_handler.py b/bot/exts/evergreen/error_handler.py new file mode 100644 index 00000000..54878c08 --- /dev/null +++ b/bot/exts/evergreen/error_handler.py @@ -0,0 +1,133 @@ +import logging +import math +import random +from typing import Iterable, Union + +from discord import Embed, Message +from discord.ext import commands +from sentry_sdk import push_scope + +from bot.constants import Colours, ERROR_REPLIES, NEGATIVE_REPLIES, Channels +from bot.utils.decorators import InChannelCheckFailure, InMonthCheckFailure +from bot.utils.exceptions import UserNotPlayingError + +log = logging.getLogger(__name__) + + +class CommandErrorHandler(commands.Cog): + """A error handler for the PythonDiscord server.""" + + def __init__(self, bot: commands.Bot): + self.bot = bot + + @staticmethod + def revert_cooldown_counter(command: commands.Command, message: Message) -> None: + """Undoes the last cooldown counter for user-error cases.""" + if command._buckets.valid: + bucket = command._buckets.get_bucket(message) + bucket._tokens = min(bucket.rate, bucket._tokens + 1) + logging.debug("Cooldown counter reverted as the command was not used correctly.") + + @staticmethod + def error_embed(message: str, title: Union[Iterable, str] = ERROR_REPLIES) -> Embed: + """Build a basic embed with red colour and either a random error title or a title provided.""" + embed = Embed(colour=Colours.soft_red) + if isinstance(title, str): + embed.title = title + else: + embed.title = random.choice(title) + embed.description = message + return embed + + @commands.Cog.listener() + async def on_command_error(self, ctx: commands.Context, error: commands.CommandError) -> None: + """Activates when a command opens an error.""" + if getattr(error, 'handled', False): + logging.debug(f"Command {ctx.command} had its error already handled locally; ignoring.") + return + + error = getattr(error, 'original', error) + logging.debug( + f"Error Encountered: {type(error).__name__} - {str(error)}, " + f"Command: {ctx.command}, " + f"Author: {ctx.author}, " + f"Channel: {ctx.channel}" + ) + + if isinstance(error, commands.CommandNotFound): + return + + if isinstance(error, (InChannelCheckFailure, InMonthCheckFailure)): + await ctx.send(embed=self.error_embed(str(error), NEGATIVE_REPLIES), delete_after=7.5) + return + + if isinstance(error, commands.UserInputError): + self.revert_cooldown_counter(ctx.command, ctx.message) + embed = self.error_embed( + f"Your input was invalid: {error}\n\nUsage:\n```{ctx.prefix}{ctx.command} {ctx.command.signature}```" + ) + await ctx.send(embed=embed) + return + + if isinstance(error, commands.CommandOnCooldown): + mins, secs = divmod(math.ceil(error.retry_after), 60) + embed = self.error_embed( + f"This command is on cooldown:\nPlease retry in {mins} minutes {secs} seconds.", + NEGATIVE_REPLIES + ) + await ctx.send(embed=embed, delete_after=7.5) + return + + if isinstance(error, commands.DisabledCommand): + await ctx.send(embed=self.error_embed("This command has been disabled.", NEGATIVE_REPLIES)) + return + + if isinstance(error, commands.NoPrivateMessage): + await ctx.send( + embed=self.error_embed( + f"This command can only be used in the server. Go to <#{Channels.community_bot_commands}> instead!", + NEGATIVE_REPLIES) + ) + return + + if isinstance(error, commands.BadArgument): + self.revert_cooldown_counter(ctx.command, ctx.message) + embed = self.error_embed( + "The argument you provided was invalid: " + f"{error}\n\nUsage:\n```{ctx.prefix}{ctx.command} {ctx.command.signature}```" + ) + await ctx.send(embed=embed) + return + + if isinstance(error, commands.CheckFailure): + await ctx.send(embed=self.error_embed("You are not authorized to use this command.", NEGATIVE_REPLIES)) + return + + if isinstance(error, UserNotPlayingError): + await ctx.send("Game not found.") + return + + with push_scope() as scope: + scope.user = { + "id": ctx.author.id, + "username": str(ctx.author) + } + + scope.set_tag("command", ctx.command.qualified_name) + scope.set_tag("message_id", ctx.message.id) + scope.set_tag("channel_id", ctx.channel.id) + + scope.set_extra("full_message", ctx.message.content) + + if ctx.guild is not None: + scope.set_extra( + "jump_to", + f"https://discordapp.com/channels/{ctx.guild.id}/{ctx.channel.id}/{ctx.message.id}" + ) + + log.exception(f"Unhandled command error: {str(error)}", exc_info=error) + + +def setup(bot: commands.Bot) -> None: + """Error handler Cog load.""" + bot.add_cog(CommandErrorHandler(bot)) -- cgit v1.2.3 From 598cb12f628547ce1542c6094908df48f4b757ec Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Wed, 24 Feb 2021 17:34:42 +0530 Subject: Make Flake8 happy (reorder imports) --- bot/exts/evergreen/error_handler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/error_handler.py b/bot/exts/evergreen/error_handler.py index 54878c08..83091ba8 100644 --- a/bot/exts/evergreen/error_handler.py +++ b/bot/exts/evergreen/error_handler.py @@ -7,7 +7,7 @@ from discord import Embed, Message from discord.ext import commands from sentry_sdk import push_scope -from bot.constants import Colours, ERROR_REPLIES, NEGATIVE_REPLIES, Channels +from bot.constants import Channels, Colours, ERROR_REPLIES, NEGATIVE_REPLIES from bot.utils.decorators import InChannelCheckFailure, InMonthCheckFailure from bot.utils.exceptions import UserNotPlayingError -- cgit v1.2.3 From 550e0e8488c77db0a0c43e2bfc948a65551f5be8 Mon Sep 17 00:00:00 2001 From: Shivansh-007 <69356296+Shivansh-007@users.noreply.github.com> Date: Wed, 24 Feb 2021 19:30:21 +0530 Subject: Correct the parentheses format Co-authored-by: Hassan Abouelela <47495861+HassanAbouelela@users.noreply.github.com> --- bot/exts/evergreen/error_handler.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/error_handler.py b/bot/exts/evergreen/error_handler.py index 83091ba8..28902503 100644 --- a/bot/exts/evergreen/error_handler.py +++ b/bot/exts/evergreen/error_handler.py @@ -86,7 +86,8 @@ class CommandErrorHandler(commands.Cog): await ctx.send( embed=self.error_embed( f"This command can only be used in the server. Go to <#{Channels.community_bot_commands}> instead!", - NEGATIVE_REPLIES) + NEGATIVE_REPLIES + ) ) return -- cgit v1.2.3 From 439873db9749f2df7f0bfe02793aac80d3a708a6 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Thu, 25 Feb 2021 10:36:59 +0530 Subject: Don't use enums for wikipedia error messages, use brackets instead of '\' for long variable values, pass in ctx.channel instead of the full ctx --- bot/exts/evergreen/wikipedia.py | 49 ++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 27 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/wikipedia.py b/bot/exts/evergreen/wikipedia.py index 0b64136f..068c4f43 100644 --- a/bot/exts/evergreen/wikipedia.py +++ b/bot/exts/evergreen/wikipedia.py @@ -1,11 +1,10 @@ import logging import re from datetime import datetime -from enum import Enum from html import unescape from typing import List, Optional -from discord import Color, Embed +from discord import Color, Embed, TextChannel from discord.ext import commands from bot.bot import Bot @@ -13,10 +12,14 @@ from bot.utils import LinePaginator log = logging.getLogger(__name__) -SEARCH_API = "https://en.wikipedia.org/w/api.php?action=query&list=search&prop=info&inprop=url&utf8=& \ - format=json&origin=*&srlimit={number_of_results}&srsearch={string}" -WIKI_THUMBNAIL = "https://upload.wikimedia.org/wikipedia/en/thumb/8/80/Wikipedia-logo-v2.svg" \ - "/330px-Wikipedia-logo-v2.svg.png" +SEARCH_API = ( + "https://en.wikipedia.org/w/api.php?action=query&list=search&prop=info&inprop=url&utf8=&" + "format=json&origin=*&srlimit={number_of_results}&srsearch={string}" +) +WIKI_THUMBNAIL = ( + "https://upload.wikimedia.org/wikipedia/en/thumb/8/80/Wikipedia-logo-v2.svg" + "/330px-Wikipedia-logo-v2.svg.png" +) WIKI_SNIPPET_REGEX = r'(|<[^>]*>)' WIKI_SEARCH_RESULT = ( "**[{name}]({url})**\n" @@ -24,20 +27,13 @@ WIKI_SEARCH_RESULT = ( ) -class WikipediaSearchErrors(Enum): - """Errors returned in wikipedia search function.""" - - no_results = "Sorry, we could not find a wikipedia article using that search term." - api_issue = "Whoops, the Wikipedia API is having some issues right now. Try again later." - - class WikipediaSearch(commands.Cog): """Get info from wikipedia.""" def __init__(self, bot: Bot): self.bot = bot - async def wiki_request(self, ctx: commands.Context, search: str) -> Optional[List[str]]: + async def wiki_request(self, channel: TextChannel, search: str) -> Optional[List[str]]: """Search wikipedia search string and return formatted first 10 pages found.""" url = SEARCH_API.format(number_of_results=10, string=search) async with self.bot.http_session.get(url=url) as resp: @@ -50,37 +46,36 @@ class WikipediaSearch(commands.Cog): lines = [] for article in results: - formatting = { - 'name': article['title'], - 'description': unescape( + line = WIKI_SEARCH_RESULT.format( + name=article['title'], + description=unescape( re.sub( WIKI_SNIPPET_REGEX, '', article['snippet'] ) ), - 'url': f"https://en.wikipedia.org/?curid={article['pageid']}" - } - line = WIKI_SEARCH_RESULT.format(**formatting) + url=f"https://en.wikipedia.org/?curid={article['pageid']}" + ) lines.append(line) return lines else: - await ctx.send( - WikipediaSearchErrors.no_results.value + await channel.send( + "Sorry, we could not find a wikipedia article using that search term." ) - return None + return else: log.info(f"Unexpected response `{resp.status}` while searching wikipedia for `{search}`") - await ctx.send( - WikipediaSearchErrors.api_issue.value + await channel.send( + "Whoops, the Wikipedia API is having some issues right now. Try again later." ) - return None + return @commands.cooldown(1, 10, commands.BucketType.user) @commands.command(name="wikipedia", aliases=["wiki"]) async def wikipedia_search_command(self, ctx: commands.Context, *, search: str) -> None: """Sends paginated top 10 results of Wikipedia search..""" - contents = await self.wiki_request(ctx, search) + contents = await self.wiki_request(ctx.channel, search) if contents: embed = Embed( -- cgit v1.2.3 From 3766b1424d7ca37ffd7d2477b7a82f192a5fedb4 Mon Sep 17 00:00:00 2001 From: xithrius Date: Thu, 25 Feb 2021 17:55:42 -0800 Subject: Added more topics. --- bot/resources/evergreen/py_topics.yaml | 53 +++++++++++++++++++++++++++------- bot/resources/evergreen/starter.yaml | 11 +++++++ 2 files changed, 54 insertions(+), 10 deletions(-) (limited to 'bot') diff --git a/bot/resources/evergreen/py_topics.yaml b/bot/resources/evergreen/py_topics.yaml index 1e53429a..4973d25a 100644 --- a/bot/resources/evergreen/py_topics.yaml +++ b/bot/resources/evergreen/py_topics.yaml @@ -3,8 +3,6 @@ # python-general 267624335836053506: - What's your favorite PEP? - - What's your current text editor/IDE, and what functionality do you like about it the most when programming in Python? - - What functionality is your text editor/IDE missing for programming Python? - What parts of your life has Python automated, if any? - Which Python project are you the most proud of making? - What made you want to learn Python? @@ -16,23 +14,34 @@ - What feature do you think should be added to Python? - Has Python helped you in school? If so, how? - What was the first thing you created with Python? + - What is your favorite Python package? + - What standard library module is really underrated? + - Have you published any packages on PyPi? If so, what are they? + - What are you currently working on in Python? + - What's your favorite script and how has it helped you in day to day activities? + - When you were first learning, what is something that stumped you? + - When you were first learning, what is a resource you wish you had? + - What is something you know now that you wish you knew when you were starting out? + - What is something simple that you still error on today? + +# algos-and-data-structs +650401909852864553: + - # async 630504881542791169: - Are there any frameworks you wish were async? - How have coroutines changed the way you write Python? + - What is your favorite async library? # c-extensions 728390945384431688: - -# computer-science -650401909852864553: - - - # databases 342318764227821568: - Where do you get your best data? + - What is your preferred database and for what use? # data-science 366673247892275221: @@ -45,11 +54,18 @@ - What feature would you be the most interested in making? - What feature would you like to see added to the library? what feature in the library do you think is redundant? - Do you think there's a way in which Discord could handle bots better? + - What's one feature you wish more developers had in their bots? + +# editors-ides +813178633006350366: + - What's your current text editor/IDE, and what functionality do you like about it the most when programming in Python? + - What functionality is your text editor/IDE missing for programming Python? # esoteric-python 470884583684964352: - What's a common part of programming we can make harder? - What are the pros and cons of messing with __magic__()? + - What's your favorite Python hack? # game-development 660625198390837248: @@ -57,7 +73,7 @@ # microcontrollers 545603026732318730: - - + - What is your favorite version of the Raspberry Pi? # networking 716325106619777044: @@ -67,23 +83,40 @@ 366674035876167691: - If you could wish for a library involving net-sec, what would it be? -# software-testing -463035728335732738: +# software-design +782713858615017503: - # tools-and-devops 463035462760792066: - What editor would you recommend to a beginner? Why? - What editor would you recommend to be the most efficient? Why? + - How often do you use GitHub Actions and workflows to automate your repositories? + - What's your favorite app on GitHub? + +# unit-testing +463035728335732738: + - # unix 491523972836360192: - - + - What's your favorite Bash command? + - What's your most used Bash command? + - How often do you update your Unix machine? + - How often do you upgrade on production? # user-interfaces 338993628049571840: - What's the most impressive Desktop Application you've made with Python so far? + - Have you ever made your own GUI? If so, how? + - Do you perfer Command Line Interfaces (CLI) or Graphic User Interfaces (GUI)? + - What's your favorite CLI (Command Line Interface) or TLI (Terminal Line Interface)? + - What's your best GUI project? # web-development 366673702533988363: - How has Python helped you in web development? + - What tools do you use for web development? + - What is your favorite API library? + - What do you use for your frontend? + - What does your stack look like? diff --git a/bot/resources/evergreen/starter.yaml b/bot/resources/evergreen/starter.yaml index 53c89364..cacaacb6 100644 --- a/bot/resources/evergreen/starter.yaml +++ b/bot/resources/evergreen/starter.yaml @@ -20,3 +20,14 @@ - If you had $100 bill in your Easter Basket, what would you do with it? - What would you do if you know you could succeed at anything you chose to do? - If you could take only three things from your house, what would they be? +- What's the best pastry? +- What's your favourite kind of soup? +- What is the most useless talent that you have? +- Would you rather fight 100 duck sized horses or one horse sized duck? +- What is your favourite colour? +- What's your favourite type of weather? +- Tea or coffee? What about milk? +- Do you speak a language other than English? +- What is your favorite TV show? +- What is your favorite media genre? +- How many years have you spent coding? -- cgit v1.2.3 From f429ce6aaa57d680893be0cbd5a7760de947aac6 Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 28 Feb 2021 19:48:13 +0000 Subject: Add issue cog to staff channels. --- bot/constants.py | 2 ++ bot/exts/evergreen/issues.py | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'bot') diff --git a/bot/constants.py b/bot/constants.py index 682ccf6f..9b7e37f8 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -124,6 +124,7 @@ class Channels(NamedTuple): hacktoberfest_2020 = 760857070781071431 voice_chat_0 = 412357430186344448 voice_chat_1 = 799647045886541885 + staff_voice = 541638762007101470 class Categories(NamedTuple): @@ -131,6 +132,7 @@ class Categories(NamedTuple): development = 411199786025484308 devprojects = 787641585624940544 media = 799054581991997460 + staff = 364918151625965579 class Client(NamedTuple): diff --git a/bot/exts/evergreen/issues.py b/bot/exts/evergreen/issues.py index 73ebe547..03d0a86b 100644 --- a/bot/exts/evergreen/issues.py +++ b/bot/exts/evergreen/issues.py @@ -24,9 +24,11 @@ if GITHUB_TOKEN := Tokens.github: REQUEST_HEADERS["Authorization"] = f"token {GITHUB_TOKEN}" WHITELISTED_CATEGORIES = ( - Categories.devprojects, Categories.media, Categories.development + Categories.devprojects, Categories.media, Categories.development, Categories.staff +) +WHITELISTED_CHANNELS_ON_MESSAGE = ( + Channels.organisation, Channels.mod_meta, Channels.mod_tools, Channels.staff_voice ) -WHITELISTED_CHANNELS_ON_MESSAGE = (Channels.organisation, Channels.mod_meta, Channels.mod_tools) CODE_BLOCK_RE = re.compile( r"^`([^`\n]+)`" # Inline codeblock -- cgit v1.2.3 From b61aa3079d7d1bcaf4e5e6754544143ce1a156a8 Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 28 Feb 2021 20:13:08 +0000 Subject: Fix ordering of categories in issues cog --- bot/exts/evergreen/issues.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/issues.py b/bot/exts/evergreen/issues.py index 03d0a86b..bbcbf611 100644 --- a/bot/exts/evergreen/issues.py +++ b/bot/exts/evergreen/issues.py @@ -24,7 +24,7 @@ if GITHUB_TOKEN := Tokens.github: REQUEST_HEADERS["Authorization"] = f"token {GITHUB_TOKEN}" WHITELISTED_CATEGORIES = ( - Categories.devprojects, Categories.media, Categories.development, Categories.staff + Categories.development, Categories.devprojects, Categories.media, Categories.staff ) WHITELISTED_CHANNELS_ON_MESSAGE = ( Channels.organisation, Channels.mod_meta, Channels.mod_tools, Channels.staff_voice -- cgit v1.2.3 From f74a49f3e686b41a52ce097a97260b263067cd68 Mon Sep 17 00:00:00 2001 From: Xithrius <15021300+Xithrius@users.noreply.github.com> Date: Sun, 28 Feb 2021 21:49:46 -0800 Subject: Removed wordy-ness of one singular question. Co-authored-by: ChrisJL --- bot/resources/evergreen/py_topics.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/resources/evergreen/py_topics.yaml b/bot/resources/evergreen/py_topics.yaml index 4973d25a..8cf9582d 100644 --- a/bot/resources/evergreen/py_topics.yaml +++ b/bot/resources/evergreen/py_topics.yaml @@ -21,7 +21,7 @@ - What's your favorite script and how has it helped you in day to day activities? - When you were first learning, what is something that stumped you? - When you were first learning, what is a resource you wish you had? - - What is something you know now that you wish you knew when you were starting out? + - What is something you know now, that you wish you knew when starting out? - What is something simple that you still error on today? # algos-and-data-structs -- cgit v1.2.3 From f9339e6043acc2161c3723624cd6ae33dce26bca Mon Sep 17 00:00:00 2001 From: xithrius Date: Sun, 28 Feb 2021 21:53:13 -0800 Subject: There's no such thing as TLI. Added TUI. --- bot/resources/evergreen/py_topics.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/resources/evergreen/py_topics.yaml b/bot/resources/evergreen/py_topics.yaml index 8cf9582d..f3b2eaa3 100644 --- a/bot/resources/evergreen/py_topics.yaml +++ b/bot/resources/evergreen/py_topics.yaml @@ -110,7 +110,7 @@ - What's the most impressive Desktop Application you've made with Python so far? - Have you ever made your own GUI? If so, how? - Do you perfer Command Line Interfaces (CLI) or Graphic User Interfaces (GUI)? - - What's your favorite CLI (Command Line Interface) or TLI (Terminal Line Interface)? + - What's your favorite CLI (Command Line Interface) or TUI (Terminal Line Interface)? - What's your best GUI project? # web-development -- cgit v1.2.3 From add46b3680d5b9570ddf464ed0674c2b5ad4474d Mon Sep 17 00:00:00 2001 From: Xithrius <15021300+Xithrius@users.noreply.github.com> Date: Sun, 28 Feb 2021 22:06:44 -0800 Subject: "colour" to "color". Co-authored-by: Hassan Abouelela <47495861+HassanAbouelela@users.noreply.github.com> --- bot/resources/evergreen/starter.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/resources/evergreen/starter.yaml b/bot/resources/evergreen/starter.yaml index cacaacb6..949220f9 100644 --- a/bot/resources/evergreen/starter.yaml +++ b/bot/resources/evergreen/starter.yaml @@ -24,7 +24,7 @@ - What's your favourite kind of soup? - What is the most useless talent that you have? - Would you rather fight 100 duck sized horses or one horse sized duck? -- What is your favourite colour? +- What is your favourite color? - What's your favourite type of weather? - Tea or coffee? What about milk? - Do you speak a language other than English? -- cgit v1.2.3 From 167774ea84ec528845a17d41065983e3ef696d12 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Tue, 2 Mar 2021 15:51:56 +0530 Subject: Fix Channel Check to use channel ids instead of channel objects, and skip channel check if debug is true --- bot/bot.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'bot') diff --git a/bot/bot.py b/bot/bot.py index 81d59706..176422aa 100644 --- a/bot/bot.py +++ b/bot/bot.py @@ -74,11 +74,16 @@ class Bot(commands.Bot): async def check_channels(self) -> None: """Verifies that all channel constants refer to channels which exist.""" await self.wait_until_guild_available() - all_channels = set(self.get_all_channels()) + + if constants.Client.debug: + log.info("Skipping Channels Check.") + return + + all_channels_ids = [channel.id for channel in set(self.get_all_channels())] for name, channel_id in vars(constants.Channels).items(): if name.startswith('_'): continue - if channel_id not in all_channels: + if channel_id not in all_channels_ids: log.error(f'Channel "{name}" with ID {channel_id} missing') async def send_log(self, title: str, details: str = None, *, icon: str = None) -> None: -- cgit v1.2.3 From 674838787fb1916dce98b50bae78159a54833c42 Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Tue, 2 Mar 2021 16:00:24 +0530 Subject: Don't use sets --- bot/bot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/bot.py b/bot/bot.py index 176422aa..e9750697 100644 --- a/bot/bot.py +++ b/bot/bot.py @@ -79,7 +79,7 @@ class Bot(commands.Bot): log.info("Skipping Channels Check.") return - all_channels_ids = [channel.id for channel in set(self.get_all_channels())] + all_channels_ids = [channel.id for channel in self.get_all_channels()] for name, channel_id in vars(constants.Channels).items(): if name.startswith('_'): continue -- cgit v1.2.3 From 1e240e7fbac71b0546ef090732c7417bab4e1563 Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Tue, 2 Mar 2021 14:27:58 -0600 Subject: initial commit of earth_photos --- bot/exts/easter/earth_photos.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 bot/exts/easter/earth_photos.py (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py new file mode 100644 index 00000000..ceffeb48 --- /dev/null +++ b/bot/exts/easter/earth_photos.py @@ -0,0 +1,27 @@ +import asyncio +import logging +import random +from unsplash.api import Api +from unsplash.auth import Auth + +import discord +from discord.ext import commands + +log = logging.getLogger(__name__) + +class EarthPhotos(commands.Cog): + """This cog contains the command for earth photos.""" + + def init(self, bot: commands.Bot): + self.bot = bot + self.current_channel = None + + @commands.command(aliases=["earth"]) + async def earth_photos(self, ctx: commands.Context): + """ + Returns a random photo of earth. + """ + + + + -- cgit v1.2.3 From 99a9d7a1b7651caea4cf1587c89485497c061387 Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Tue, 2 Mar 2021 15:22:39 -0600 Subject: Update earth_photos.py --- bot/exts/easter/earth_photos.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index ceffeb48..436b39a7 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -1,14 +1,24 @@ import asyncio import logging import random -from unsplash.api import Api -from unsplash.auth import Auth +from unsplash.api import Api as uApi +from unsplash.auth import Auth as uAuth import discord from discord.ext import commands +from bot.constants import Tokens + log = logging.getLogger(__name__) +UnClient_id = Tokens.UNSPLASH_API + +UnClient_secret = Tokens.UNSPLASH_SECRET + +redirect_uri = "urn:ietf:wg:oauth:2.0:oob" + +unsplash_auth = uAuth(client_id, + class EarthPhotos(commands.Cog): """This cog contains the command for earth photos.""" @@ -19,7 +29,7 @@ class EarthPhotos(commands.Cog): @commands.command(aliases=["earth"]) async def earth_photos(self, ctx: commands.Context): """ - Returns a random photo of earth. + Returns a random photo of earth, sourced from Unsplash. """ -- cgit v1.2.3 From 0260ad04af6e98c7fd804c58913412b6b936eb73 Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Tue, 2 Mar 2021 21:39:01 -0600 Subject: finished function --- Pipfile | 1 + Pipfile.lock | 26 +++++++++++++++++--------- bot/constants.py | 1 + bot/exts/easter/earth_photos.py | 35 +++++++++++++++++++---------------- 4 files changed, 38 insertions(+), 25 deletions(-) (limited to 'bot') diff --git a/Pipfile b/Pipfile index e7e01a31..1a2d464e 100644 --- a/Pipfile +++ b/Pipfile @@ -15,6 +15,7 @@ PyYAML = "~=5.3.1" "discord.py" = {extras = ["voice"], version = "~=1.5.1"} async-rediscache = {extras = ["fakeredis"], version = "~=0.1.4"} emojis = "~=0.6.0" +requests = "~=2.25.1" [dev-packages] flake8 = "~=3.8" diff --git a/Pipfile.lock b/Pipfile.lock index ec801979..34cd08cf 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "b4aaaacbab13179145e36d7b86c736db512286f6cce8e513cc30c48d68fe3810" + "sha256": "53409f1c6726e95cf348740b1dc55124b77a1f327aea273dce041b5056270b2e" }, "pipfile-spec": 6, "requires": { @@ -238,11 +238,11 @@ }, "idna": { "hashes": [ - "sha256:5205d03e7bcbb919cc9c19885f9920d622ca52448306f2377daede5cf3faac16", - "sha256:c5b02147e01ea9920e6b0a3f1f7bb833612d507592c837a6c49552768f4054e1" + "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6", + "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0" ], - "markers": "python_version >= '3.4'", - "version": "==3.1" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.10" }, "multidict": { "hashes": [ @@ -412,6 +412,14 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==3.5.3" }, + "requests": { + "hashes": [ + "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804", + "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e" + ], + "index": "pypi", + "version": "==2.25.1" + }, "sentry-sdk": { "hashes": [ "sha256:4ae8d1ced6c67f1c8ea51d82a16721c166c489b76876c9f2c202b8a50334b237", @@ -585,11 +593,11 @@ }, "identify": { "hashes": [ - "sha256:de7129142a5c86d75a52b96f394d94d96d497881d2aaf8eafe320cdbe8ac4bcc", - "sha256:e0dae57c0397629ce13c289f6ddde0204edf518f557bfdb1e56474aa143e77c3" + "sha256:9cdd81e5d2b6e76c3006d5226316dd947bd6324fbeebb881bec489202fa09d3a", + "sha256:b99aa309329c4fea679463eb35d169f3fbe13e66e9dd6162ad1856cbeb03dcbd" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.5.14" + "markers": "python_full_version >= '3.6.1'", + "version": "==2.0.0" }, "mccabe": { "hashes": [ diff --git a/bot/constants.py b/bot/constants.py index db34b55a..f8ea5743 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -271,6 +271,7 @@ class Tokens(NamedTuple): igdb_client_id = environ.get("IGDB_CLIENT_ID") igdb_client_secret = environ.get("IGDB_CLIENT_SECRET") github = environ.get("GITHUB_TOKEN") + unsplash_key = environ.get("UNSPLASH_KEY") class Wolfram(NamedTuple): diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index 436b39a7..478502eb 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -1,8 +1,5 @@ -import asyncio import logging -import random -from unsplash.api import Api as uApi -from unsplash.auth import Auth as uAuth +import requests import discord from discord.ext import commands @@ -11,27 +8,33 @@ from bot.constants import Tokens log = logging.getLogger(__name__) -UnClient_id = Tokens.UNSPLASH_API +UnClient_id = Tokens.unsplash_key -UnClient_secret = Tokens.UNSPLASH_SECRET - -redirect_uri = "urn:ietf:wg:oauth:2.0:oob" - -unsplash_auth = uAuth(client_id, class EarthPhotos(commands.Cog): """This cog contains the command for earth photos.""" - + def init(self, bot: commands.Bot): self.bot = bot self.current_channel = None - + @commands.command(aliases=["earth"]) async def earth_photos(self, ctx: commands.Context): """ Returns a random photo of earth, sourced from Unsplash. """ - - - - + photorequest = requests.get("https://api.unsplash.com/photos/random?query=earth&client_id=" + UnClient_id) + photojson = photorequest.json() + photourls = photojson.get('urls') + urltosend = photourls.get('regular') + userjson = photojson.get('user') + userName = userjson.get('name') + embed = discord.Embed(title="Earth Photo", description="A photo of Earth from Unsplash.", color=0x66ff00) + embed.set_image(url=urltosend) + embed.set_footer(text="Image by " + userName + " on Unsplash.") + await ctx.send(embed=embed) + + +def setup(bot: commands.Bot) -> None: + """Cog load""" + bot.add_cog(EarthPhotos(bot)) -- cgit v1.2.3 From 51f16ed0a4e1ce43d7ce4cef1701a886d1b8492d Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Tue, 2 Mar 2021 21:58:27 -0600 Subject: Update earth_photos.py --- bot/exts/easter/earth_photos.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index 478502eb..2ca43e42 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -1,9 +1,10 @@ -import logging -import requests - import discord from discord.ext import commands +import logging + +import requests + from bot.constants import Tokens log = logging.getLogger(__name__) @@ -15,6 +16,7 @@ class EarthPhotos(commands.Cog): """This cog contains the command for earth photos.""" def init(self, bot: commands.Bot): + """Init function.""" self.bot = bot self.current_channel = None @@ -28,13 +30,13 @@ class EarthPhotos(commands.Cog): photourls = photojson.get('urls') urltosend = photourls.get('regular') userjson = photojson.get('user') - userName = userjson.get('name') + username = userjson.get('name') embed = discord.Embed(title="Earth Photo", description="A photo of Earth from Unsplash.", color=0x66ff00) embed.set_image(url=urltosend) - embed.set_footer(text="Image by " + userName + " on Unsplash.") + embed.set_footer(text="Image by " + username + " on Unsplash.") await ctx.send(embed=embed) def setup(bot: commands.Bot) -> None: - """Cog load""" + """Cog load.""" bot.add_cog(EarthPhotos(bot)) -- cgit v1.2.3 From 286d40bb887246216da23857b4eeb8364fcbf9c7 Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Tue, 2 Mar 2021 22:04:47 -0600 Subject: linting changes --- bot/exts/easter/earth_photos.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index 2ca43e42..e660112f 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -1,8 +1,10 @@ import discord -from discord.ext import commands import logging +from discord.ext import commands + + import requests from bot.constants import Tokens @@ -22,9 +24,7 @@ class EarthPhotos(commands.Cog): @commands.command(aliases=["earth"]) async def earth_photos(self, ctx: commands.Context): - """ - Returns a random photo of earth, sourced from Unsplash. - """ + """Returns a random photo of earth, sourced from Unsplash.""" photorequest = requests.get("https://api.unsplash.com/photos/random?query=earth&client_id=" + UnClient_id) photojson = photorequest.json() photourls = photojson.get('urls') -- cgit v1.2.3 From 8220661e8ef65ef4bbe92613ed2d3f273d43d76f Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Tue, 2 Mar 2021 22:09:10 -0600 Subject: more linting fixes --- bot/exts/easter/earth_photos.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index e660112f..c9cfc9c8 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -1,11 +1,9 @@ -import discord - import logging -from discord.ext import commands - +import discord import requests +from discord.ext import commands from bot.constants import Tokens -- cgit v1.2.3 From da54e5181cbf2ab3406be4a8ab9628e346d3c328 Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Tue, 2 Mar 2021 22:15:57 -0600 Subject: lint fixes --- bot/exts/easter/earth_photos.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index c9cfc9c8..909fcbd8 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -1,7 +1,6 @@ import logging import discord - import requests from discord.ext import commands @@ -15,13 +14,13 @@ UnClient_id = Tokens.unsplash_key class EarthPhotos(commands.Cog): """This cog contains the command for earth photos.""" - def init(self, bot: commands.Bot): + def init(self, bot: commands.Bot) -> None: """Init function.""" self.bot = bot self.current_channel = None @commands.command(aliases=["earth"]) - async def earth_photos(self, ctx: commands.Context): + async def earth_photos(self, ctx: commands.Context) -> None: """Returns a random photo of earth, sourced from Unsplash.""" photorequest = requests.get("https://api.unsplash.com/photos/random?query=earth&client_id=" + UnClient_id) photojson = photorequest.json() -- cgit v1.2.3 From 029f5f0d6b38f70000013ca52c859a3486cdf544 Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Wed, 3 Mar 2021 07:14:06 -0600 Subject: Update bot/exts/easter/earth_photos.py Co-authored-by: Shivansh-007 <69356296+Shivansh-007@users.noreply.github.com> --- bot/exts/easter/earth_photos.py | 1 - 1 file changed, 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index 909fcbd8..b41b277c 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -15,7 +15,6 @@ class EarthPhotos(commands.Cog): """This cog contains the command for earth photos.""" def init(self, bot: commands.Bot) -> None: - """Init function.""" self.bot = bot self.current_channel = None -- cgit v1.2.3 From 883405e6f419ebfe4799086bf4e7516fd1588c4d Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Wed, 3 Mar 2021 07:43:41 -0600 Subject: init to __init__ Co-authored-by: Shivansh-007 <69356296+Shivansh-007@users.noreply.github.com> --- bot/exts/easter/earth_photos.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index b41b277c..db295285 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -14,7 +14,7 @@ UnClient_id = Tokens.unsplash_key class EarthPhotos(commands.Cog): """This cog contains the command for earth photos.""" - def init(self, bot: commands.Bot) -> None: + def __init__(self, bot: commands.Bot) -> None: self.bot = bot self.current_channel = None -- cgit v1.2.3 From 246e5bd7109ba906162989e42c77d68402359106 Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Wed, 3 Mar 2021 09:26:48 -0600 Subject: Fix docstrings Co-authored-by: Shivansh-007 <69356296+Shivansh-007@users.noreply.github.com> --- bot/exts/easter/earth_photos.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index db295285..4c319eaa 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -34,5 +34,5 @@ class EarthPhotos(commands.Cog): def setup(bot: commands.Bot) -> None: - """Cog load.""" + """Load the Earth Photos cog.""" bot.add_cog(EarthPhotos(bot)) -- cgit v1.2.3 From 4a0401ddb322fba53e2025a63fdf8d0a52e12076 Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Wed, 3 Mar 2021 09:32:47 -0600 Subject: Update earth_photos.py --- bot/exts/easter/earth_photos.py | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index 4c319eaa..52bbaf36 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -1,13 +1,9 @@ -import logging - +import aiohttp import discord -import requests from discord.ext import commands from bot.constants import Tokens -log = logging.getLogger(__name__) - UnClient_id = Tokens.unsplash_key @@ -21,16 +17,14 @@ class EarthPhotos(commands.Cog): @commands.command(aliases=["earth"]) async def earth_photos(self, ctx: commands.Context) -> None: """Returns a random photo of earth, sourced from Unsplash.""" - photorequest = requests.get("https://api.unsplash.com/photos/random?query=earth&client_id=" + UnClient_id) - photojson = photorequest.json() - photourls = photojson.get('urls') - urltosend = photourls.get('regular') - userjson = photojson.get('user') - username = userjson.get('name') - embed = discord.Embed(title="Earth Photo", description="A photo of Earth from Unsplash.", color=0x66ff00) - embed.set_image(url=urltosend) - embed.set_footer(text="Image by " + username + " on Unsplash.") - await ctx.send(embed=embed) + async with ctx.typing(): + async with aiohttp.ClientSession as session: + async with session.get( + 'https://api.unsplash.com/photos/random?query=earth&client_id=' + UnClientId + ) as r: + jsondata = await r.json() + await ctx.send("Still a placeholder") + def setup(bot: commands.Bot) -> None: -- cgit v1.2.3 From a2c68caf0e39e6947372d303dcc707f26f1a744f Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Wed, 3 Mar 2021 09:57:07 -0600 Subject: Update earth_photos.py --- bot/exts/easter/earth_photos.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index 52bbaf36..adae0dcd 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -20,10 +20,18 @@ class EarthPhotos(commands.Cog): async with ctx.typing(): async with aiohttp.ClientSession as session: async with session.get( - 'https://api.unsplash.com/photos/random?query=earth&client_id=' + UnClientId - ) as r: + 'https://api.unsplash.com/photos/random?query=earth&client_id=' + UnClientId) as r: jsondata = await r.json() - await ctx.send("Still a placeholder") + linksdata = jsondata.get("urls") + downloadlinksdata = jsondata.get("links") + async with session.get( + downloadlinksdata.get("download_location") + "?client_id=" + UnClient_id) as er: + pass + await ctx.send("Still a work in progress") + + + + -- cgit v1.2.3 From 01a1624b14cc5d60b2e76871361e14f9cbfd69ce Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Wed, 3 Mar 2021 09:57:49 -0600 Subject: asyncio start --- bot/exts/easter/earth_photos.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index adae0dcd..26beda79 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -27,7 +27,7 @@ class EarthPhotos(commands.Cog): async with session.get( downloadlinksdata.get("download_location") + "?client_id=" + UnClient_id) as er: pass - await ctx.send("Still a work in progress") + await ctx.send("Still a work in progress, coming soon.") -- cgit v1.2.3 From 3b0949c96926fa30aa650bfd9c9a43e4fd52521f Mon Sep 17 00:00:00 2001 From: Kronifer Date: Wed, 3 Mar 2021 16:39:05 +0000 Subject: linting --- Pipfile | 1 + Pipfile.lock | 76 ++++++++++++++++++++++++++++++++++++++--- bot/exts/easter/earth_photos.py | 14 ++++---- 3 files changed, 79 insertions(+), 12 deletions(-) (limited to 'bot') diff --git a/Pipfile b/Pipfile index 1a2d464e..1d1df3d7 100644 --- a/Pipfile +++ b/Pipfile @@ -16,6 +16,7 @@ PyYAML = "~=5.3.1" async-rediscache = {extras = ["fakeredis"], version = "~=0.1.4"} emojis = "~=0.6.0" requests = "~=2.25.1" +pre-commit = "*" [dev-packages] flake8 = "~=3.8" diff --git a/Pipfile.lock b/Pipfile.lock index 34cd08cf..b58db761 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "53409f1c6726e95cf348740b1dc55124b77a1f327aea273dce041b5056270b2e" + "sha256": "434b76f6a372bf3ddc418d7b6bdba4d8906cbebb76553ffebf0b15d572e83487" }, "pipfile-spec": 6, "requires": { @@ -50,6 +50,13 @@ ], "version": "==1.3.1" }, + "appdirs": { + "hashes": [ + "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41", + "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128" + ], + "version": "==1.4.4" + }, "arrow": { "hashes": [ "sha256:e098abbd9af3665aea81bdd6c869e93af4feb078e98468dd351c383af187aac5", @@ -143,6 +150,14 @@ ], "version": "==1.14.5" }, + "cfgv": { + "hashes": [ + "sha256:32e43d604bbe7896fe7c248a9c2276447dbef840feb28fe20494f62af110211d", + "sha256:cf22deb93d4bcf92f345a5c3cd39d3d41d6340adc60c78bbbd6588c384fda6a1" + ], + "markers": "python_full_version >= '3.6.1'", + "version": "==3.2.0" + }, "chardet": { "hashes": [ "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", @@ -161,6 +176,13 @@ "index": "pypi", "version": "==1.5.1" }, + "distlib": { + "hashes": [ + "sha256:8c09de2c67b3e7deef7184574fc060ab8a793e7adbb183d942c389c8b13c52fb", + "sha256:edf6116872c863e1aa9d5bb7cb5e05a022c519a4594dc703843343a9ddd9bff1" + ], + "version": "==0.3.1" + }, "emojis": { "hashes": [ "sha256:7da34c8a78ae262fd68cef9e2c78a3c1feb59784489eeea0f54ba1d4b7111c7c", @@ -176,6 +198,13 @@ ], "version": "==1.4.5" }, + "filelock": { + "hashes": [ + "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59", + "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836" + ], + "version": "==3.0.12" + }, "fuzzywuzzy": { "hashes": [ "sha256:45016e92264780e58972dca1b3d939ac864b78437422beecebb3095f8efd00e8", @@ -236,6 +265,14 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.1.0" }, + "identify": { + "hashes": [ + "sha256:2179e7359471ab55729f201b3fdf7dc2778e221f868410fedcb0987b791ba552", + "sha256:2a5fdf2f5319cc357eda2550bea713a404392495961022cf2462624ce62f0f46" + ], + "markers": "python_full_version >= '3.6.1'", + "version": "==2.1.0" + }, "idna": { "hashes": [ "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6", @@ -267,6 +304,13 @@ "markers": "python_version >= '3.5'", "version": "==4.7.6" }, + "nodeenv": { + "hashes": [ + "sha256:5304d424c529c997bc888453aeaa6362d242b6b4631e90f3d4bf1b290f1c84a9", + "sha256:ab45090ae383b716c4ef89e690c41ff8c2b257b85b309f01f3654df3d084bd7c" + ], + "version": "==1.5.0" + }, "pillow": { "hashes": [ "sha256:0295442429645fa16d05bd567ef5cff178482439c9aad0411d3f0ce9b88b3a6f", @@ -301,6 +345,14 @@ "index": "pypi", "version": "==7.2.0" }, + "pre-commit": { + "hashes": [ + "sha256:16212d1fde2bed88159287da88ff03796863854b04dc9f838a55979325a3d20e", + "sha256:399baf78f13f4de82a29b649afd74bef2c4e28eb4f021661fc7f29246e8c7a3a" + ], + "index": "pypi", + "version": "==2.10.1" + }, "pycares": { "hashes": [ "sha256:050f00b39ed77ea8a4e555f09417d4b1a6b5baa24bb9531a3e15d003d2319b3f", @@ -451,6 +503,14 @@ "markers": "python_version >= '3.0'", "version": "==2.2" }, + "toml": { + "hashes": [ + "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", + "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" + ], + "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==0.10.2" + }, "urllib3": { "hashes": [ "sha256:1b465e494e3e0d8939b50680403e3aedaa2bc434b7d5af64dfd3c958d7f5ae80", @@ -459,6 +519,14 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", "version": "==1.26.3" }, + "virtualenv": { + "hashes": [ + "sha256:147b43894e51dd6bba882cf9c282447f780e2251cd35172403745fc381a0a80d", + "sha256:2be72df684b74df0ea47679a7df93fd0e04e72520022c57b479d8f881485dbe3" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==20.4.2" + }, "yarl": { "hashes": [ "sha256:040b237f58ff7d800e6e0fd89c8439b841f777dd99b4a9cca04d6935564b9409", @@ -593,11 +661,11 @@ }, "identify": { "hashes": [ - "sha256:9cdd81e5d2b6e76c3006d5226316dd947bd6324fbeebb881bec489202fa09d3a", - "sha256:b99aa309329c4fea679463eb35d169f3fbe13e66e9dd6162ad1856cbeb03dcbd" + "sha256:2179e7359471ab55729f201b3fdf7dc2778e221f868410fedcb0987b791ba552", + "sha256:2a5fdf2f5319cc357eda2550bea713a404392495961022cf2462624ce62f0f46" ], "markers": "python_full_version >= '3.6.1'", - "version": "==2.0.0" + "version": "==2.1.0" }, "mccabe": { "hashes": [ diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index 26beda79..8e90c9e7 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -20,19 +20,17 @@ class EarthPhotos(commands.Cog): async with ctx.typing(): async with aiohttp.ClientSession as session: async with session.get( - 'https://api.unsplash.com/photos/random?query=earth&client_id=' + UnClientId) as r: + 'https://api.unsplash.com/photos/random?query=earth&client_id=' + UnClient_id) as r: jsondata = await r.json() linksdata = jsondata.get("urls") + embedlink = linksdata.get("full") downloadlinksdata = jsondata.get("links") async with session.get( downloadlinksdata.get("download_location") + "?client_id=" + UnClient_id) as er: - pass - await ctx.send("Still a work in progress, coming soon.") - - - - - + er.status() + embed = discord.Embed(title="In progress") + embed.set_photo(url=embedlink) + await ctx.send(embed=embed) def setup(bot: commands.Bot) -> None: -- cgit v1.2.3 From 443c623548caf8edb82d0b9cfe41afcf594f0161 Mon Sep 17 00:00:00 2001 From: Kronifer Date: Wed, 3 Mar 2021 16:48:19 +0000 Subject: final lint fix --- bot/exts/easter/earth_photos.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index 8e90c9e7..e3d5936e 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -20,13 +20,13 @@ class EarthPhotos(commands.Cog): async with ctx.typing(): async with aiohttp.ClientSession as session: async with session.get( - 'https://api.unsplash.com/photos/random?query=earth&client_id=' + UnClient_id) as r: + 'https://api.unsplash.com/photos/random?query=earth&client_id=' + UnClient_id) as r: jsondata = await r.json() linksdata = jsondata.get("urls") embedlink = linksdata.get("full") downloadlinksdata = jsondata.get("links") async with session.get( - downloadlinksdata.get("download_location") + "?client_id=" + UnClient_id) as er: + downloadlinksdata.get("download_location") + "?client_id=" + UnClient_id) as er: er.status() embed = discord.Embed(title="In progress") embed.set_photo(url=embedlink) -- cgit v1.2.3 From f0cd29587f29731286be8c29d1ee0ca20d37d42f Mon Sep 17 00:00:00 2001 From: Kronifer Date: Wed, 3 Mar 2021 17:07:20 +0000 Subject: possible final update --- bot/exts/easter/earth_photos.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index e3d5936e..0ac470ce 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -18,19 +18,27 @@ class EarthPhotos(commands.Cog): async def earth_photos(self, ctx: commands.Context) -> None: """Returns a random photo of earth, sourced from Unsplash.""" async with ctx.typing(): - async with aiohttp.ClientSession as session: + async with aiohttp.ClientSession() as session: async with session.get( 'https://api.unsplash.com/photos/random?query=earth&client_id=' + UnClient_id) as r: jsondata = await r.json() linksdata = jsondata.get("urls") embedlink = linksdata.get("full") downloadlinksdata = jsondata.get("links") + userdata = jsondata.get("user") + username = userdata.get("name") + userlinks = userdata.get("links") + profile = userlinks.get("html") async with session.get( downloadlinksdata.get("download_location") + "?client_id=" + UnClient_id) as er: - er.status() - embed = discord.Embed(title="In progress") - embed.set_photo(url=embedlink) - await ctx.send(embed=embed) + er.status + embed = discord.Embed( + title="Earth Photo", + description="A photo of earth from Unsplash.", + color=0x66ff00) + embed.set_image(url=embedlink) + embed.add_field(title="Author", value="Made by [" + username + "](" + profile + ") on Unsplash.") + await ctx.send(embed=embed) def setup(bot: commands.Bot) -> None: -- cgit v1.2.3 From b2ee1b9e79766b8cfe7b45670f6c86e7166ee84f Mon Sep 17 00:00:00 2001 From: Kronifer Date: Wed, 3 Mar 2021 20:20:22 +0000 Subject: fstrings, colours, and self.bot --- Pipfile | 2 -- bot/constants.py | 1 + bot/exts/easter/earth_photos.py | 48 ++++++++++++++++++++--------------------- 3 files changed, 25 insertions(+), 26 deletions(-) (limited to 'bot') diff --git a/Pipfile b/Pipfile index 1d1df3d7..e7e01a31 100644 --- a/Pipfile +++ b/Pipfile @@ -15,8 +15,6 @@ PyYAML = "~=5.3.1" "discord.py" = {extras = ["voice"], version = "~=1.5.1"} async-rediscache = {extras = ["fakeredis"], version = "~=0.1.4"} emojis = "~=0.6.0" -requests = "~=2.25.1" -pre-commit = "*" [dev-packages] flake8 = "~=3.8" diff --git a/bot/constants.py b/bot/constants.py index f8ea5743..c570b17f 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -158,6 +158,7 @@ class Colours: soft_orange = 0xf9cb54 soft_red = 0xcd6d6d yellow = 0xf9f586 + grass_green = 0x66ff00 class Emojis: diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index 0ac470ce..a49e666c 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -1,8 +1,8 @@ -import aiohttp import discord from discord.ext import commands from bot.constants import Tokens +from bot.constants import Colours UnClient_id = Tokens.unsplash_key @@ -10,35 +10,35 @@ UnClient_id = Tokens.unsplash_key class EarthPhotos(commands.Cog): """This cog contains the command for earth photos.""" - def __init__(self, bot: commands.Bot) -> None: + def __init__(self, bot: commands.Bot): self.bot = bot - self.current_channel = None @commands.command(aliases=["earth"]) async def earth_photos(self, ctx: commands.Context) -> None: """Returns a random photo of earth, sourced from Unsplash.""" async with ctx.typing(): - async with aiohttp.ClientSession() as session: - async with session.get( - 'https://api.unsplash.com/photos/random?query=earth&client_id=' + UnClient_id) as r: - jsondata = await r.json() - linksdata = jsondata.get("urls") - embedlink = linksdata.get("full") - downloadlinksdata = jsondata.get("links") - userdata = jsondata.get("user") - username = userdata.get("name") - userlinks = userdata.get("links") - profile = userlinks.get("html") - async with session.get( - downloadlinksdata.get("download_location") + "?client_id=" + UnClient_id) as er: - er.status - embed = discord.Embed( - title="Earth Photo", - description="A photo of earth from Unsplash.", - color=0x66ff00) - embed.set_image(url=embedlink) - embed.add_field(title="Author", value="Made by [" + username + "](" + profile + ") on Unsplash.") - await ctx.send(embed=embed) + async with self.bot.http_session.get( + 'https://api.unsplash.com/photos/random', + params={"query": "planet_earth", "client_id": UnClient_id}) as r: + jsondata = await r.json() + linksdata = jsondata.get("urls") + embedlink = linksdata.get("full") + downloadlinksdata = jsondata.get("links") + userdata = jsondata.get("user") + username = userdata.get("name") + userlinks = userdata.get("links") + profile = userlinks.get("html") + async with self.bot.http_session.get( + downloadlinksdata.get("download_location"), + params={"client_id": UnClient_id}) as er: + er.status + embed = discord.Embed( + title="Earth Photo", + description="A photo of earth from Unsplash.", + color=Colours.grass_green) + embed.set_image(url=embedlink) + embed.add_field(name="Author", value=f"Made by [{username}]({profile}) on Unsplash.") + await ctx.send(embed=embed) def setup(bot: commands.Bot) -> None: -- cgit v1.2.3 From 4cf72b014efbd8141e30482984e68e65c08e312d Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Wed, 3 Mar 2021 14:28:43 -0600 Subject: Fixed import --- bot/exts/easter/earth_photos.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index a49e666c..b496cbea 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -1,8 +1,8 @@ import discord from discord.ext import commands -from bot.constants import Tokens from bot.constants import Colours +from bot.constants import Tokens UnClient_id = Tokens.unsplash_key -- cgit v1.2.3 From 6c46dca3525758f1c1841f1dba312bb45c28531e Mon Sep 17 00:00:00 2001 From: Kronifer Date: Wed, 3 Mar 2021 22:27:37 +0000 Subject: minor change to getting image --- bot/exts/easter/earth_photos.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index a49e666c..66780f6a 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -19,10 +19,10 @@ class EarthPhotos(commands.Cog): async with ctx.typing(): async with self.bot.http_session.get( 'https://api.unsplash.com/photos/random', - params={"query": "planet_earth", "client_id": UnClient_id}) as r: + params={"query": "earth", "client_id": UnClient_id}) as r: jsondata = await r.json() linksdata = jsondata.get("urls") - embedlink = linksdata.get("full") + embedlink = linksdata.get("regular") downloadlinksdata = jsondata.get("links") userdata = jsondata.get("user") username = userdata.get("name") -- cgit v1.2.3 From 01c380754e7466654924238dcee2f2077dd752a7 Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Wed, 3 Mar 2021 19:03:40 -0600 Subject: Format change Co-authored-by: Shivansh-007 <69356296+Shivansh-007@users.noreply.github.com> --- bot/exts/easter/earth_photos.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index efc5081a..a544ab59 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -35,7 +35,8 @@ class EarthPhotos(commands.Cog): embed = discord.Embed( title="Earth Photo", description="A photo of earth from Unsplash.", - color=Colours.grass_green) + color=Colours.grass_green + ) embed.set_image(url=embedlink) embed.add_field(name="Author", value=f"Made by [{username}]({profile}) on Unsplash.") await ctx.send(embed=embed) -- cgit v1.2.3 From fa38d70fc16e34ff3aff58bfbc7533f586a8eb97 Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Wed, 3 Mar 2021 19:05:16 -0600 Subject: More formatting Co-authored-by: Shivansh-007 <69356296+Shivansh-007@users.noreply.github.com> --- bot/exts/easter/earth_photos.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index a544ab59..f0c57fc5 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -30,7 +30,8 @@ class EarthPhotos(commands.Cog): profile = userlinks.get("html") async with self.bot.http_session.get( downloadlinksdata.get("download_location"), - params={"client_id": UnClient_id}) as er: + params={"client_id": UnClient_id} + ) as er: er.status embed = discord.Embed( title="Earth Photo", -- cgit v1.2.3 From 825080e805787afc1f36a80b4fa3f73040ebdc75 Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Wed, 3 Mar 2021 19:05:37 -0600 Subject: Format change Co-authored-by: Shivansh-007 <69356296+Shivansh-007@users.noreply.github.com> --- bot/exts/easter/earth_photos.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index f0c57fc5..6bfc26b0 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -19,7 +19,8 @@ class EarthPhotos(commands.Cog): async with ctx.typing(): async with self.bot.http_session.get( 'https://api.unsplash.com/photos/random', - params={"query": "earth", "client_id": UnClient_id}) as r: + params={"query": "earth", "client_id": UnClient_id} + ) as r: jsondata = await r.json() linksdata = jsondata.get("urls") embedlink = linksdata.get("regular") -- cgit v1.2.3 From 05e18c02cd076a70e3aac370e7d120a16c84aab7 Mon Sep 17 00:00:00 2001 From: Kronifer Date: Thu, 4 Mar 2021 01:31:14 +0000 Subject: Revert "Format change" This reverts commit 825080e805787afc1f36a80b4fa3f73040ebdc75. --- bot/exts/easter/earth_photos.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index 6bfc26b0..f0c57fc5 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -19,8 +19,7 @@ class EarthPhotos(commands.Cog): async with ctx.typing(): async with self.bot.http_session.get( 'https://api.unsplash.com/photos/random', - params={"query": "earth", "client_id": UnClient_id} - ) as r: + params={"query": "earth", "client_id": UnClient_id}) as r: jsondata = await r.json() linksdata = jsondata.get("urls") embedlink = linksdata.get("regular") -- cgit v1.2.3 From 60712f67c3e0f77023a481e5cbf0ce9816a7368e Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Wed, 3 Mar 2021 20:16:59 -0600 Subject: requested changes by @Shivansh-007 --- bot/exts/easter/earth_photos.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index f0c57fc5..001f8f41 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -31,8 +31,8 @@ class EarthPhotos(commands.Cog): async with self.bot.http_session.get( downloadlinksdata.get("download_location"), params={"client_id": UnClient_id} - ) as er: - er.status + ) as _: + pass embed = discord.Embed( title="Earth Photo", description="A photo of earth from Unsplash.", -- cgit v1.2.3 From e222ece92b4d14f4a9bb148f28acf9770da44d1b Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Thu, 4 Mar 2021 10:35:38 -0600 Subject: Changes requested by @ChrisLovering --- bot/exts/easter/earth_photos.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index 001f8f41..3ab8e7d9 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -1,10 +1,12 @@ +import logging + import discord from discord.ext import commands from bot.constants import Colours from bot.constants import Tokens -UnClient_id = Tokens.unsplash_key +log = logging.getLogger(__name__) class EarthPhotos(commands.Cog): @@ -19,7 +21,7 @@ class EarthPhotos(commands.Cog): async with ctx.typing(): async with self.bot.http_session.get( 'https://api.unsplash.com/photos/random', - params={"query": "earth", "client_id": UnClient_id}) as r: + params={"query": "earth", "client_id": Tokens.unsplash_access_key}) as r: jsondata = await r.json() linksdata = jsondata.get("urls") embedlink = linksdata.get("regular") @@ -30,9 +32,10 @@ class EarthPhotos(commands.Cog): profile = userlinks.get("html") async with self.bot.http_session.get( downloadlinksdata.get("download_location"), - params={"client_id": UnClient_id} - ) as _: + params={"client_id": Tokens.unsplash_access_key} + ) as er: pass + embed = discord.Embed( title="Earth Photo", description="A photo of earth from Unsplash.", @@ -45,4 +48,7 @@ class EarthPhotos(commands.Cog): def setup(bot: commands.Bot) -> None: """Load the Earth Photos cog.""" + if not Tokens.unsplash_access_key: + log.warning("No Unsplash access key found. Cog not loading.") + return bot.add_cog(EarthPhotos(bot)) -- cgit v1.2.3 From 512a5b3f085510d5862589ecc21bd253cb219207 Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Thu, 4 Mar 2021 10:37:53 -0600 Subject: Changes requested by @ChrisLovering --- bot/constants.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/constants.py b/bot/constants.py index c570b17f..721defc8 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -272,7 +272,7 @@ class Tokens(NamedTuple): igdb_client_id = environ.get("IGDB_CLIENT_ID") igdb_client_secret = environ.get("IGDB_CLIENT_SECRET") github = environ.get("GITHUB_TOKEN") - unsplash_key = environ.get("UNSPLASH_KEY") + unsplash_access_key = environ.get("UNSPLASH_KEY") class Wolfram(NamedTuple): -- cgit v1.2.3 From 8b05f80392174a1a8b47e872b955d59bdcd4472f Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Thu, 4 Mar 2021 10:40:42 -0600 Subject: small lint fix --- bot/exts/easter/earth_photos.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index 3ab8e7d9..beb16772 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -33,7 +33,7 @@ class EarthPhotos(commands.Cog): async with self.bot.http_session.get( downloadlinksdata.get("download_location"), params={"client_id": Tokens.unsplash_access_key} - ) as er: + ) as _: pass embed = discord.Embed( -- cgit v1.2.3 From f22aa5bd3f706751556def22d5660cdc8d93fde1 Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Thu, 4 Mar 2021 10:56:06 -0600 Subject: Format fix Co-authored-by: Shivansh-007 <69356296+Shivansh-007@users.noreply.github.com> --- bot/exts/easter/earth_photos.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index beb16772..3abedd0c 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -21,7 +21,8 @@ class EarthPhotos(commands.Cog): async with ctx.typing(): async with self.bot.http_session.get( 'https://api.unsplash.com/photos/random', - params={"query": "earth", "client_id": Tokens.unsplash_access_key}) as r: + params={"query": "earth", "client_id": Tokens.unsplash_access_key} + ) as r: jsondata = await r.json() linksdata = jsondata.get("urls") embedlink = linksdata.get("regular") -- cgit v1.2.3 From 1e1f4035f14592d7beaf93cbd3ae8e3895de588c Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Thu, 4 Mar 2021 10:56:36 -0600 Subject: String upgrade Co-authored-by: Shivansh-007 <69356296+Shivansh-007@users.noreply.github.com> --- bot/exts/easter/earth_photos.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index 3abedd0c..d3b21644 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -39,7 +39,7 @@ class EarthPhotos(commands.Cog): embed = discord.Embed( title="Earth Photo", - description="A photo of earth from Unsplash.", + description="A photo of Earth 🌎 from Unsplash.", color=Colours.grass_green ) embed.set_image(url=embedlink) -- cgit v1.2.3 From 3fa4049b0c16777c7a9349dc9058d89a4a44b5c7 Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Thu, 4 Mar 2021 10:58:25 -0600 Subject: Update earth_photos.py --- bot/exts/easter/earth_photos.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index d3b21644..71fb1313 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -43,7 +43,7 @@ class EarthPhotos(commands.Cog): color=Colours.grass_green ) embed.set_image(url=embedlink) - embed.add_field(name="Author", value=f"Made by [{username}]({profile}) on Unsplash.") + embed.add_field(name="Author", value=f"Photo by [{username}]({profile}) on Unsplash.") await ctx.send(embed=embed) -- cgit v1.2.3 From c25381fffd3b42bd1345dd9a910218c70877d2d3 Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Thu, 4 Mar 2021 10:59:36 -0600 Subject: suggestion by @Shivansh-007 --- bot/exts/easter/earth_photos.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index 71fb1313..1cf2d11a 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -44,7 +44,7 @@ class EarthPhotos(commands.Cog): ) embed.set_image(url=embedlink) embed.add_field(name="Author", value=f"Photo by [{username}]({profile}) on Unsplash.") - await ctx.send(embed=embed) + await ctx.send(embed=embed) def setup(bot: commands.Bot) -> None: -- cgit v1.2.3 From 68ff4f3a524e90099e6953bd601321623e789e66 Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Thu, 4 Mar 2021 11:04:05 -0600 Subject: clarification in some areas --- bot/exts/easter/earth_photos.py | 1 + 1 file changed, 1 insertion(+) (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index 1cf2d11a..c1704e12 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -31,6 +31,7 @@ class EarthPhotos(commands.Cog): username = userdata.get("name") userlinks = userdata.get("links") profile = userlinks.get("html") + # Extra request as per Unsplash Guidelines async with self.bot.http_session.get( downloadlinksdata.get("download_location"), params={"client_id": Tokens.unsplash_access_key} -- cgit v1.2.3 From 55e33789830c00fc970c74be142857f90678cda7 Mon Sep 17 00:00:00 2001 From: MrKomodoDragon Date: Thu, 4 Mar 2021 11:20:37 -0800 Subject: Add link to discussion for suggesting facts in Embed --- bot/exts/evergreen/pythonfacts.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/evergreen/pythonfacts.py b/bot/exts/evergreen/pythonfacts.py index 11b258f9..fb96a19d 100644 --- a/bot/exts/evergreen/pythonfacts.py +++ b/bot/exts/evergreen/pythonfacts.py @@ -20,7 +20,12 @@ class PythonFacts(commands.Cog): @commands.command(name='pythonfact', aliases=['pyfact']) async def get_python_fact(self, ctx: commands.Context) -> None: """Sends a Random fun fact about Python.""" - embed = discord.Embed(title='Python Facts', description=next(FACTS), colour=next(COLORS)) + embed = discord.Embed(title='Python Facts', + description=next(FACTS), + colour=next(COLORS)) + embed.add_field(name='Suggestions', + value="Want to suggest more facts? " + "Suggest more facts [here!](https://github.com/python-discord/meta/discussions/93)") await ctx.send(embed=embed) -- cgit v1.2.3 From cce1b2cb25b572ac3e976b190d7eae417240ae76 Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Thu, 4 Mar 2021 13:26:42 -0600 Subject: API guideline fix for Unsplash --- bot/exts/easter/earth_photos.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index c1704e12..39bb627e 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -31,7 +31,6 @@ class EarthPhotos(commands.Cog): username = userdata.get("name") userlinks = userdata.get("links") profile = userlinks.get("html") - # Extra request as per Unsplash Guidelines async with self.bot.http_session.get( downloadlinksdata.get("download_location"), params={"client_id": Tokens.unsplash_access_key} @@ -44,7 +43,9 @@ class EarthPhotos(commands.Cog): color=Colours.grass_green ) embed.set_image(url=embedlink) - embed.add_field(name="Author", value=f"Photo by [{username}]({profile}) on Unsplash.") + embed.add_field(name="Author", + value=f"Photo by [{username}]({profile}?utm_source=sir_lancebot&utm_medium=referral)\ + on [Unsplash](https://unsplash.com?utm_source=sir_lancebot&utm_medium=referral).") await ctx.send(embed=embed) -- cgit v1.2.3 From 6b8a81e7a698eb362b4bea7bb73ef369d589cbfc Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Thu, 4 Mar 2021 13:30:17 -0600 Subject: whitespace fix --- bot/exts/easter/earth_photos.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index 39bb627e..9bcca583 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -39,11 +39,11 @@ class EarthPhotos(commands.Cog): embed = discord.Embed( title="Earth Photo", - description="A photo of Earth 🌎 from Unsplash.", + description="A photo of Earth 🌎 from Unsplash.", color=Colours.grass_green ) embed.set_image(url=embedlink) - embed.add_field(name="Author", + embed.add_field(name="Author", value=f"Photo by [{username}]({profile}?utm_source=sir_lancebot&utm_medium=referral)\ on [Unsplash](https://unsplash.com?utm_source=sir_lancebot&utm_medium=referral).") await ctx.send(embed=embed) -- cgit v1.2.3 From 43d42c9fc254e79ecb8e98e42ff4ea9aa43c707a Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Thu, 4 Mar 2021 13:44:31 -0600 Subject: linting fix --- bot/exts/easter/earth_photos.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index 9bcca583..26f3d115 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -21,7 +21,7 @@ class EarthPhotos(commands.Cog): async with ctx.typing(): async with self.bot.http_session.get( 'https://api.unsplash.com/photos/random', - params={"query": "earth", "client_id": Tokens.unsplash_access_key} + params={"query": "planet_earth", "client_id": Tokens.unsplash_access_key} ) as r: jsondata = await r.json() linksdata = jsondata.get("urls") @@ -31,6 +31,8 @@ class EarthPhotos(commands.Cog): username = userdata.get("name") userlinks = userdata.get("links") profile = userlinks.get("html") + # Referral flags + rf = "?utm_source=sir_lancebot&utm_medium=referral" async with self.bot.http_session.get( downloadlinksdata.get("download_location"), params={"client_id": Tokens.unsplash_access_key} @@ -39,13 +41,13 @@ class EarthPhotos(commands.Cog): embed = discord.Embed( title="Earth Photo", - description="A photo of Earth 🌎 from Unsplash.", + description="A photo of Earth 🌎 from Unsplash.", color=Colours.grass_green ) embed.set_image(url=embedlink) embed.add_field(name="Author", - value=f"Photo by [{username}]({profile}?utm_source=sir_lancebot&utm_medium=referral)\ - on [Unsplash](https://unsplash.com?utm_source=sir_lancebot&utm_medium=referral).") + value=f"Photo by [{username}]({profile}" + rf + ") \ +on [Unsplash](https://unsplash.com?" + rf + ").") await ctx.send(embed=embed) -- cgit v1.2.3 From e6f2d51cfc35ae8bafc160fb3449911457442252 Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Thu, 4 Mar 2021 13:53:45 -0600 Subject: style guidelines --- bot/exts/easter/earth_photos.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index 26f3d115..96282d24 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -45,9 +45,11 @@ class EarthPhotos(commands.Cog): color=Colours.grass_green ) embed.set_image(url=embedlink) - embed.add_field(name="Author", - value=f"Photo by [{username}]({profile}" + rf + ") \ -on [Unsplash](https://unsplash.com?" + rf + ").") + embed.add_field( + name="Author", + value=f"Photo by [{username}]({profile}{rf}) \ + on [Unsplash](https://unsplash.com{rf})." + ) await ctx.send(embed=embed) -- cgit v1.2.3 From 1ae9948c04257c27fb2e71e5ae03a05bcd1db60e Mon Sep 17 00:00:00 2001 From: Kronifer <44979306+Kronifer@users.noreply.github.com> Date: Thu, 4 Mar 2021 13:57:26 -0600 Subject: single space fix --- bot/exts/easter/earth_photos.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index 96282d24..12fe6f1c 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -41,7 +41,7 @@ class EarthPhotos(commands.Cog): embed = discord.Embed( title="Earth Photo", - description="A photo of Earth 🌎 from Unsplash.", + description="A photo of Earth 🌎 from Unsplash.", color=Colours.grass_green ) embed.set_image(url=embedlink) -- cgit v1.2.3 From 1669b50e026678fd8e9fe6f72677e1de5943dd66 Mon Sep 17 00:00:00 2001 From: MrKomodoDragon Date: Thu, 4 Mar 2021 12:18:25 -0800 Subject: Remove "Want to suggest a fact?" for consistency --- bot/exts/evergreen/pythonfacts.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'bot') diff --git a/bot/exts/evergreen/pythonfacts.py b/bot/exts/evergreen/pythonfacts.py index fb96a19d..457c2fd3 100644 --- a/bot/exts/evergreen/pythonfacts.py +++ b/bot/exts/evergreen/pythonfacts.py @@ -24,8 +24,7 @@ class PythonFacts(commands.Cog): description=next(FACTS), colour=next(COLORS)) embed.add_field(name='Suggestions', - value="Want to suggest more facts? " - "Suggest more facts [here!](https://github.com/python-discord/meta/discussions/93)") + value="Suggest more facts [here!](https://github.com/python-discord/meta/discussions/93)") await ctx.send(embed=embed) -- cgit v1.2.3 From 334885c1b98ac4dcd475baac358eb8981a65b9c5 Mon Sep 17 00:00:00 2001 From: Dillon Runke <44979306+Kronifer@users.noreply.github.com> Date: Thu, 4 Mar 2021 16:17:42 -0600 Subject: Update earth_photos.py --- bot/exts/easter/earth_photos.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bot') diff --git a/bot/exts/easter/earth_photos.py b/bot/exts/easter/earth_photos.py index 12fe6f1c..60e34b15 100644 --- a/bot/exts/easter/earth_photos.py +++ b/bot/exts/easter/earth_photos.py @@ -32,7 +32,7 @@ class EarthPhotos(commands.Cog): userlinks = userdata.get("links") profile = userlinks.get("html") # Referral flags - rf = "?utm_source=sir_lancebot&utm_medium=referral" + rf = "?utm_source=Sir%20Lancebot&utm_medium=referral" async with self.bot.http_session.get( downloadlinksdata.get("download_location"), params={"client_id": Tokens.unsplash_access_key} -- cgit v1.2.3 From bd49374ca6efad79b97d891882b05b8568f10fb4 Mon Sep 17 00:00:00 2001 From: MrKomodoDragon <74436682+MrKomodoDragon@users.noreply.github.com> Date: Thu, 4 Mar 2021 14:39:47 -0800 Subject: Remove arrows (whoopsies)! --- bot/constants.py | 3 --- 1 file changed, 3 deletions(-) (limited to 'bot') diff --git a/bot/constants.py b/bot/constants.py index f6e09ae7..b8e30a7c 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -158,12 +158,9 @@ class Colours: soft_orange = 0xf9cb54 soft_red = 0xcd6d6d yellow = 0xf9f586 -<<<<<<< master python_blue = 0x4B8BBE python_yellow = 0xFFD43B -======= grass_green = 0x66ff00 ->>>>>>> master class Emojis: -- cgit v1.2.3