aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bot/decorators.py28
-rw-r--r--bot/exts/info/reddit.py6
-rw-r--r--bot/exts/recruitment/talentpool/_review.py12
-rw-r--r--bot/exts/utils/snekbox.py10
-rw-r--r--bot/resources/stars.json7
-rw-r--r--bot/resources/tags/identity.md24
6 files changed, 74 insertions, 13 deletions
diff --git a/bot/decorators.py b/bot/decorators.py
index e971a5bd3..f65ec4103 100644
--- a/bot/decorators.py
+++ b/bot/decorators.py
@@ -107,11 +107,19 @@ def has_no_roles(*roles: t.Union[str, int]) -> t.Callable:
return commands.check(predicate)
-def redirect_output(destination_channel: int, bypass_roles: t.Container[int] = None) -> t.Callable:
+def redirect_output(
+ destination_channel: int,
+ bypass_roles: t.Optional[t.Container[int]] = None,
+ channels: t.Optional[t.Container[int]] = None,
+ categories: t.Optional[t.Container[int]] = None,
+ ping_user: bool = True
+) -> t.Callable:
"""
Changes the channel in the context of the command to redirect the output to a certain channel.
- Redirect is bypassed if the author has a role to bypass redirection.
+ Redirect is bypassed if the author has a bypass role or if it is in a channel that can bypass redirection.
+
+ If ping_user is False, it will not send a message in the destination channel.
This decorator must go before (below) the `command` decorator.
"""
@@ -119,7 +127,7 @@ def redirect_output(destination_channel: int, bypass_roles: t.Container[int] = N
@command_wraps(func)
async def inner(self: Cog, ctx: Context, *args, **kwargs) -> None:
if ctx.channel.id == destination_channel:
- log.trace(f"Command {ctx.command.name} was invoked in destination_channel, not redirecting")
+ log.trace(f"Command {ctx.command} was invoked in destination_channel, not redirecting")
await func(self, ctx, *args, **kwargs)
return
@@ -128,12 +136,24 @@ def redirect_output(destination_channel: int, bypass_roles: t.Container[int] = N
await func(self, ctx, *args, **kwargs)
return
+ elif channels and ctx.channel.id not in channels:
+ log.trace(f"{ctx.author} used {ctx.command} in a channel that can bypass output redirection")
+ await func(self, ctx, *args, **kwargs)
+ return
+
+ elif categories and ctx.channel.category.id not in categories:
+ log.trace(f"{ctx.author} used {ctx.command} in a category that can bypass output redirection")
+ await func(self, ctx, *args, **kwargs)
+ return
+
redirect_channel = ctx.guild.get_channel(destination_channel)
old_channel = ctx.channel
log.trace(f"Redirecting output of {ctx.author}'s command '{ctx.command.name}' to {redirect_channel.name}")
ctx.channel = redirect_channel
- await ctx.channel.send(f"Here's the output of your command, {ctx.author.mention}")
+
+ if ping_user:
+ await ctx.send(f"Here's the output of your command, {ctx.author.mention}")
asyncio.create_task(func(self, ctx, *args, **kwargs))
message = await old_channel.send(
diff --git a/bot/exts/info/reddit.py b/bot/exts/info/reddit.py
index 6790be762..e1f0c5f9f 100644
--- a/bot/exts/info/reddit.py
+++ b/bot/exts/info/reddit.py
@@ -4,6 +4,7 @@ import random
import textwrap
from collections import namedtuple
from datetime import datetime, timedelta
+from html import unescape
from typing import List
from aiohttp import BasicAuth, ClientError
@@ -179,8 +180,7 @@ class Reddit(Cog):
for post in posts:
data = post["data"]
- text = data["selftext"]
- if text:
+ if text := unescape(data["selftext"]):
text = textwrap.shorten(text, width=128, placeholder="...")
text += "\n" # Add newline to separate embed info
@@ -188,7 +188,7 @@ class Reddit(Cog):
comments = data["num_comments"]
author = data["author"]
- title = textwrap.shorten(data["title"], width=64, placeholder="...")
+ title = textwrap.shorten(unescape(data["title"]), width=64, placeholder="...")
# Normal brackets interfere with Markdown.
title = escape_markdown(title).replace("[", "⦋").replace("]", "⦌")
link = self.URL + data["permalink"]
diff --git a/bot/exts/recruitment/talentpool/_review.py b/bot/exts/recruitment/talentpool/_review.py
index 11aa3b62b..4ae1c5ad6 100644
--- a/bot/exts/recruitment/talentpool/_review.py
+++ b/bot/exts/recruitment/talentpool/_review.py
@@ -57,7 +57,7 @@ class Reviewer:
"""Schedules a single user for review."""
log.trace(f"Scheduling review of user with ID {user_id}")
- user_data = self._pool.watched_users[user_id]
+ user_data = self._pool.watched_users.get(user_id)
inserted_at = isoparse(user_data['inserted_at']).replace(tzinfo=None)
review_at = inserted_at + timedelta(days=MAX_DAYS_IN_POOL)
@@ -81,14 +81,18 @@ class Reviewer:
await message.add_reaction(reaction)
if update_database:
- nomination = self._pool.watched_users[user_id]
+ nomination = self._pool.watched_users.get(user_id)
await self.bot.api_client.patch(f"{self._pool.api_endpoint}/{nomination['id']}", json={"reviewed": True})
async def make_review(self, user_id: int) -> typing.Tuple[str, Optional[Emoji]]:
"""Format a generic review of a user and return it with the seen emoji."""
log.trace(f"Formatting the review of {user_id}")
- nomination = self._pool.watched_users[user_id]
+ # Since `watched_users` is a defaultdict, we should take care
+ # not to accidentally insert the IDs of users that have no
+ # active nominated by using the `watched_users.get(user_id)`
+ # instead of `watched_users[user_id]`.
+ nomination = self._pool.watched_users.get(user_id)
if not nomination:
log.trace(f"There doesn't appear to be an active nomination for {user_id}")
return "", None
@@ -303,7 +307,7 @@ class Reviewer:
await ctx.send(f":x: Can't find a currently nominated user with id `{user_id}`")
return False
- nomination = self._pool.watched_users[user_id]
+ nomination = self._pool.watched_users.get(user_id)
if nomination["reviewed"]:
await ctx.send(":x: This nomination was already reviewed, but here's a cookie :cookie:")
return False
diff --git a/bot/exts/utils/snekbox.py b/bot/exts/utils/snekbox.py
index da95240bb..b1f1ba6a8 100644
--- a/bot/exts/utils/snekbox.py
+++ b/bot/exts/utils/snekbox.py
@@ -13,7 +13,7 @@ from discord.ext.commands import Cog, Context, command, guild_only
from bot.bot import Bot
from bot.constants import Categories, Channels, Roles, URLs
-from bot.decorators import not_in_blacklist
+from bot.decorators import redirect_output
from bot.utils import send_to_paste_service
from bot.utils.messages import wait_for_deletion
@@ -280,7 +280,13 @@ class Snekbox(Cog):
@command(name="eval", aliases=("e",))
@guild_only()
- @not_in_blacklist(channels=NO_EVAL_CHANNELS, categories=NO_EVAL_CATEGORIES, override_roles=EVAL_ROLES)
+ @redirect_output(
+ destination_channel=Channels.bot_commands,
+ bypass_roles=EVAL_ROLES,
+ categories=NO_EVAL_CATEGORIES,
+ channels=NO_EVAL_CHANNELS,
+ ping_user=False
+ )
async def eval_command(self, ctx: Context, *, code: str = None) -> None:
"""
Run Python code and get the results.
diff --git a/bot/resources/stars.json b/bot/resources/stars.json
index 5ecad0213..3eb0a9d0d 100644
--- a/bot/resources/stars.json
+++ b/bot/resources/stars.json
@@ -20,6 +20,7 @@
"Céline Dion",
"Cher",
"Christina Aguilera",
+ "Darude",
"David Bowie",
"Donna Summer",
"Drake",
@@ -31,11 +32,14 @@
"Flo Rida",
"Frank Sinatra",
"Garth Brooks",
+ "George Harrison",
"George Michael",
"George Strait",
+ "Guido Van Rossum",
"James Taylor",
"Janet Jackson",
"Jay-Z",
+ "John Lennon",
"Johnny Cash",
"Johnny Hallyday",
"Julio Iglesias",
@@ -61,13 +65,16 @@
"Pink",
"Prince",
"Reba McEntire",
+ "Rick Astley",
"Rihanna",
+ "Ringo Starr",
"Robbie Williams",
"Rod Stewart",
"Santana",
"Shania Twain",
"Stevie Wonder",
"Taylor Swift",
+ "The Weeknd",
"Tim McGraw",
"Tina Turner",
"Tom Petty",
diff --git a/bot/resources/tags/identity.md b/bot/resources/tags/identity.md
new file mode 100644
index 000000000..fb2010759
--- /dev/null
+++ b/bot/resources/tags/identity.md
@@ -0,0 +1,24 @@
+**Identity vs. Equality**
+
+Should I be using `is` or `==`?
+
+To check if two objects are equal, use the equality operator (`==`).
+```py
+x = 5
+if x == 5:
+ print("x equals 5")
+if x == 3:
+ print("x equals 3")
+# Prints 'x equals 5'
+```
+To check if two objects are actually the same thing in memory, use the identity comparison operator (`is`).
+```py
+list_1 = [1, 2, 3]
+list_2 = [1, 2, 3]
+if list_1 is [1, 2, 3]:
+ print("list_1 is list_2")
+reference_to_list_1 = list_1
+if list_1 is reference_to_list_1:
+ print("list_1 is reference_to_list_1")
+# Prints 'list_1 is reference_to_list_1'
+```