aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar ChrisJL <[email protected]>2021-08-24 18:27:45 +0100
committerGravatar GitHub <[email protected]>2021-08-24 18:27:45 +0100
commit8d01d11742d10d7c89f2d078629f997903fc080b (patch)
tree079a5b8a28aca2273350e4071db06d829bd3888a
parentRemove TagContentConverter (diff)
parentMerge pull request #1776 from python-discord/community-partners-access (diff)
Merge branch 'main' into converter-typehints
-rw-r--r--bot/constants.py3
-rw-r--r--bot/exts/info/help.py4
-rw-r--r--bot/exts/info/information.py10
-rw-r--r--bot/exts/moderation/stream.py13
-rw-r--r--bot/exts/recruitment/talentpool/_cog.py6
-rw-r--r--bot/exts/utils/internal.py7
-rw-r--r--bot/exts/utils/ping.py4
-rw-r--r--bot/exts/utils/reminders.py14
-rw-r--r--bot/exts/utils/utils.py12
-rw-r--r--bot/rules/mentions.py6
-rw-r--r--config-default.yml3
-rw-r--r--tests/bot/exts/info/test_information.py4
-rw-r--r--tests/bot/rules/test_mentions.py26
13 files changed, 75 insertions, 37 deletions
diff --git a/bot/constants.py b/bot/constants.py
index 407646b28..80e01b174 100644
--- a/bot/constants.py
+++ b/bot/constants.py
@@ -689,7 +689,7 @@ class VideoPermission(metaclass=YAMLGetter):
# Debug mode
-DEBUG_MODE = 'local' in os.environ.get("SITE_URL", "local")
+DEBUG_MODE: bool = _CONFIG_YAML["debug"] == "true"
# Paths
BOT_DIR = os.path.dirname(__file__)
@@ -698,6 +698,7 @@ PROJECT_ROOT = os.path.abspath(os.path.join(BOT_DIR, os.pardir))
# Default role combinations
MODERATION_ROLES = Guild.moderation_roles
STAFF_ROLES = Guild.staff_roles
+STAFF_PARTNERS_COMMUNITY_ROLES = STAFF_ROLES + [Roles.partners, Roles.python_community]
# Channel combinations
MODERATION_CHANNELS = Guild.moderation_channels
diff --git a/bot/exts/info/help.py b/bot/exts/info/help.py
index 0235bbaf3..21a6cf752 100644
--- a/bot/exts/info/help.py
+++ b/bot/exts/info/help.py
@@ -10,7 +10,7 @@ from rapidfuzz import fuzz, process
from rapidfuzz.utils import default_process
from bot import constants
-from bot.constants import Channels, STAFF_ROLES
+from bot.constants import Channels, STAFF_PARTNERS_COMMUNITY_ROLES
from bot.decorators import redirect_output
from bot.pagination import LinePaginator
from bot.utils.messages import wait_for_deletion
@@ -54,7 +54,7 @@ class CustomHelpCommand(HelpCommand):
def __init__(self):
super().__init__(command_attrs={"help": "Shows help for bot commands"})
- @redirect_output(destination_channel=Channels.bot_commands, bypass_roles=STAFF_ROLES)
+ @redirect_output(destination_channel=Channels.bot_commands, bypass_roles=STAFF_PARTNERS_COMMUNITY_ROLES)
async def command_callback(self, ctx: Context, *, command: str = None) -> None:
"""Attempts to match the provided query with a valid command or cog."""
# the only reason we need to tamper with this is because d.py does not support "categories",
diff --git a/bot/exts/info/information.py b/bot/exts/info/information.py
index 8bef6a8cd..38b436b7d 100644
--- a/bot/exts/info/information.py
+++ b/bot/exts/info/information.py
@@ -95,7 +95,7 @@ class Information(Cog):
{python_general.mention} cooldown: {python_general.slowmode_delay}s
""")
- @has_any_role(*constants.STAFF_ROLES)
+ @has_any_role(*constants.STAFF_PARTNERS_COMMUNITY_ROLES)
@command(name="roles")
async def roles_info(self, ctx: Context) -> None:
"""Returns a list of all roles and their corresponding IDs."""
@@ -115,7 +115,7 @@ class Information(Cog):
await LinePaginator.paginate(role_list, ctx, embed, empty=False)
- @has_any_role(*constants.STAFF_ROLES)
+ @has_any_role(*constants.STAFF_PARTNERS_COMMUNITY_ROLES)
@command(name="role")
async def role_info(self, ctx: Context, *roles: Union[Role, str]) -> None:
"""
@@ -232,7 +232,7 @@ class Information(Cog):
return
# Will redirect to #bot-commands if it fails.
- if in_whitelist_check(ctx, roles=constants.STAFF_ROLES):
+ if in_whitelist_check(ctx, roles=constants.STAFF_PARTNERS_COMMUNITY_ROLES):
embed = await self.create_user_embed(ctx, user)
await ctx.send(embed=embed)
@@ -455,9 +455,9 @@ class Information(Cog):
# remove trailing whitespace
return out.rstrip()
- @cooldown_with_role_bypass(2, 60 * 3, BucketType.member, bypass_roles=constants.STAFF_ROLES)
+ @cooldown_with_role_bypass(2, 60 * 3, BucketType.member, bypass_roles=constants.STAFF_PARTNERS_COMMUNITY_ROLES)
@group(invoke_without_command=True)
- @in_whitelist(channels=(constants.Channels.bot_commands,), roles=constants.STAFF_ROLES)
+ @in_whitelist(channels=(constants.Channels.bot_commands,), roles=constants.STAFF_PARTNERS_COMMUNITY_ROLES)
async def raw(self, ctx: Context, *, message: Message, json: bool = False) -> None:
"""Shows information about the raw API response."""
if ctx.author not in message.channel.members:
diff --git a/bot/exts/moderation/stream.py b/bot/exts/moderation/stream.py
index 07ee4099e..01d2614b0 100644
--- a/bot/exts/moderation/stream.py
+++ b/bot/exts/moderation/stream.py
@@ -9,7 +9,10 @@ from async_rediscache import RedisCache
from discord.ext import commands
from bot.bot import Bot
-from bot.constants import Colours, Emojis, Guild, MODERATION_ROLES, Roles, STAFF_ROLES, VideoPermission
+from bot.constants import (
+ Colours, Emojis, Guild, MODERATION_ROLES, Roles,
+ STAFF_PARTNERS_COMMUNITY_ROLES, VideoPermission
+)
from bot.converters import Expiry
from bot.pagination import LinePaginator
from bot.utils.scheduling import Scheduler
@@ -193,17 +196,17 @@ class Stream(commands.Cog):
@commands.command(aliases=('lstream',))
@commands.has_any_role(*MODERATION_ROLES)
async def liststream(self, ctx: commands.Context) -> None:
- """Lists all non-staff users who have permission to stream."""
- non_staff_members_with_stream = [
+ """Lists all users who aren't staff, partners or members of the python community and have stream permissions."""
+ non_staff_partners_community_members_with_stream = [
member
for member in ctx.guild.get_role(Roles.video).members
- if not any(role.id in STAFF_ROLES for role in member.roles)
+ if not any(role.id in STAFF_PARTNERS_COMMUNITY_ROLES for role in member.roles)
]
# List of tuples (UtcPosixTimestamp, str)
# So that the list can be sorted on the UtcPosixTimestamp before the message is passed to the paginator.
streamer_info = []
- for member in non_staff_members_with_stream:
+ for member in non_staff_partners_community_members_with_stream:
if revoke_time := await self.task_cache.get(member.id):
# Member only has temporary streaming perms
revoke_delta = Arrow.utcfromtimestamp(revoke_time).humanize()
diff --git a/bot/exts/recruitment/talentpool/_cog.py b/bot/exts/recruitment/talentpool/_cog.py
index 5c1a1cd3f..c297f70c2 100644
--- a/bot/exts/recruitment/talentpool/_cog.py
+++ b/bot/exts/recruitment/talentpool/_cog.py
@@ -263,7 +263,7 @@ class TalentPool(WatchChannel, Cog, name="Talentpool"):
}
)
- msg = f"✅ The nomination for {user} has been added to the talent pool"
+ msg = f"✅ The nomination for {user.mention} has been added to the talent pool"
if history:
msg += f"\n\n({len(history)} previous nominations in total)"
@@ -311,7 +311,7 @@ class TalentPool(WatchChannel, Cog, name="Talentpool"):
return
if await self.unwatch(user.id, reason):
- await ctx.send(f":white_check_mark: Messages sent by {user} will no longer be relayed")
+ await ctx.send(f":white_check_mark: Messages sent by {user.mention} will no longer be relayed")
else:
await ctx.send(":x: The specified user does not have an active nomination")
@@ -344,7 +344,7 @@ class TalentPool(WatchChannel, Cog, name="Talentpool"):
return
if not any(entry["actor"] == actor.id for entry in nomination["entries"]):
- await ctx.send(f":x: {actor} doesn't have an entry in this nomination.")
+ await ctx.send(f":x: {actor.mention} doesn't have an entry in this nomination.")
return
self.log.trace(f"Changing reason for nomination with id {nomination_id} of actor {actor} to {repr(reason)}")
diff --git a/bot/exts/utils/internal.py b/bot/exts/utils/internal.py
index 6f2da3131..5d2cd7611 100644
--- a/bot/exts/utils/internal.py
+++ b/bot/exts/utils/internal.py
@@ -11,10 +11,10 @@ from io import StringIO
from typing import Any, Optional, Tuple
import discord
-from discord.ext.commands import Cog, Context, group, has_any_role
+from discord.ext.commands import Cog, Context, group, has_any_role, is_owner
from bot.bot import Bot
-from bot.constants import Roles
+from bot.constants import DEBUG_MODE, Roles
from bot.utils import find_nth_occurrence, send_to_paste_service
log = logging.getLogger(__name__)
@@ -33,6 +33,9 @@ class Internal(Cog):
self.socket_event_total = 0
self.socket_events = Counter()
+ if DEBUG_MODE:
+ self.eval.add_check(is_owner().predicate)
+
@Cog.listener()
async def on_socket_response(self, msg: dict) -> None:
"""When a websocket event is received, increase our counters."""
diff --git a/bot/exts/utils/ping.py b/bot/exts/utils/ping.py
index c6d7bd900..cf0e3265e 100644
--- a/bot/exts/utils/ping.py
+++ b/bot/exts/utils/ping.py
@@ -5,7 +5,7 @@ from discord import Embed
from discord.ext import commands
from bot.bot import Bot
-from bot.constants import Channels, STAFF_ROLES, URLs
+from bot.constants import Channels, STAFF_PARTNERS_COMMUNITY_ROLES, URLs
from bot.decorators import in_whitelist
DESCRIPTIONS = (
@@ -23,7 +23,7 @@ class Latency(commands.Cog):
self.bot = bot
@commands.command()
- @in_whitelist(channels=(Channels.bot_commands,), roles=STAFF_ROLES)
+ @in_whitelist(channels=(Channels.bot_commands,), roles=STAFF_PARTNERS_COMMUNITY_ROLES)
async def ping(self, ctx: commands.Context) -> None:
"""
Gets different measures of latency within the bot.
diff --git a/bot/exts/utils/reminders.py b/bot/exts/utils/reminders.py
index 144f7b537..90ad7ef2e 100644
--- a/bot/exts/utils/reminders.py
+++ b/bot/exts/utils/reminders.py
@@ -11,7 +11,10 @@ from dateutil.parser import isoparse
from discord.ext.commands import Cog, Context, Greedy, group
from bot.bot import Bot
-from bot.constants import Guild, Icons, MODERATION_ROLES, POSITIVE_REPLIES, Roles, STAFF_ROLES
+from bot.constants import (
+ Guild, Icons, MODERATION_ROLES, POSITIVE_REPLIES,
+ Roles, STAFF_PARTNERS_COMMUNITY_ROLES
+)
from bot.converters import Duration, UserMentionOrID
from bot.pagination import LinePaginator
from bot.utils.checks import has_any_role_check, has_no_roles_check
@@ -111,7 +114,7 @@ class Reminders(Cog):
If mentions aren't allowed, also return the type of mention(s) disallowed.
"""
- if await has_no_roles_check(ctx, *STAFF_ROLES):
+ if await has_no_roles_check(ctx, *STAFF_PARTNERS_COMMUNITY_ROLES):
return False, "members/roles"
elif await has_no_roles_check(ctx, *MODERATION_ROLES):
return all(isinstance(mention, discord.Member) for mention in mentions), "roles"
@@ -137,7 +140,7 @@ class Reminders(Cog):
"""Converts Role and Member ids to their corresponding objects if possible."""
guild = self.bot.get_guild(Guild.id)
for mention_id in mention_ids:
- if (mentionable := (guild.get_member(mention_id) or guild.get_role(mention_id))):
+ if mentionable := (guild.get_member(mention_id) or guild.get_role(mention_id)):
yield mentionable
def schedule_reminder(self, reminder: dict) -> None:
@@ -226,8 +229,9 @@ class Reminders(Cog):
Expiration is parsed per: http://strftime.org/
"""
- # If the user is not staff, we need to verify whether or not to make a reminder at all.
- if await has_no_roles_check(ctx, *STAFF_ROLES):
+ # If the user is not staff, partner or part of the python community,
+ # we need to verify whether or not to make a reminder at all.
+ if await has_no_roles_check(ctx, *STAFF_PARTNERS_COMMUNITY_ROLES):
# If they don't have permission to set a reminder in this channel
if ctx.channel.id not in WHITELISTED_CHANNELS:
diff --git a/bot/exts/utils/utils.py b/bot/exts/utils/utils.py
index 28c7ec27b..0139a6ad3 100644
--- a/bot/exts/utils/utils.py
+++ b/bot/exts/utils/utils.py
@@ -9,7 +9,7 @@ from discord.ext.commands import BadArgument, Cog, Context, clean_content, comma
from discord.utils import snowflake_time
from bot.bot import Bot
-from bot.constants import Channels, MODERATION_ROLES, Roles, STAFF_ROLES
+from bot.constants import Channels, MODERATION_ROLES, Roles, STAFF_PARTNERS_COMMUNITY_ROLES
from bot.converters import Snowflake
from bot.decorators import in_whitelist
from bot.pagination import LinePaginator
@@ -49,20 +49,22 @@ class Utils(Cog):
self.bot = bot
@command()
- @in_whitelist(channels=(Channels.bot_commands, Channels.discord_py), roles=STAFF_ROLES)
+ @in_whitelist(channels=(Channels.bot_commands, Channels.discord_py), roles=STAFF_PARTNERS_COMMUNITY_ROLES)
async def charinfo(self, ctx: Context, *, characters: str) -> None:
"""Shows you information on up to 50 unicode characters."""
match = re.match(r"<(a?):(\w+):(\d+)>", characters)
if match:
- return await messages.send_denial(
+ await messages.send_denial(
ctx,
"**Non-Character Detected**\n"
"Only unicode characters can be processed, but a custom Discord emoji "
"was found. Please remove it and try again."
)
+ return
if len(characters) > 50:
- return await messages.send_denial(ctx, f"Too many characters ({len(characters)}/50)")
+ await messages.send_denial(ctx, f"Too many characters ({len(characters)}/50)")
+ return
def get_info(char: str) -> Tuple[str, str]:
digit = f"{ord(char):x}"
@@ -156,7 +158,7 @@ class Utils(Cog):
await ctx.send(embed=embed)
@command(aliases=("snf", "snfl", "sf"))
- @in_whitelist(channels=(Channels.bot_commands,), roles=STAFF_ROLES)
+ @in_whitelist(channels=(Channels.bot_commands,), roles=STAFF_PARTNERS_COMMUNITY_ROLES)
async def snowflake(self, ctx: Context, *snowflakes: Snowflake) -> None:
"""Get Discord snowflake creation time."""
if not snowflakes:
diff --git a/bot/rules/mentions.py b/bot/rules/mentions.py
index 79725a4b1..6f5addad1 100644
--- a/bot/rules/mentions.py
+++ b/bot/rules/mentions.py
@@ -13,7 +13,11 @@ async def apply(
if msg.author == last_message.author
)
- total_recent_mentions = sum(len(msg.mentions) for msg in relevant_messages)
+ total_recent_mentions = sum(
+ not user.bot
+ for msg in relevant_messages
+ for user in msg.mentions
+ )
if total_recent_mentions > config['max']:
return (
diff --git a/config-default.yml b/config-default.yml
index eaf8e0ad7..8e0b97a51 100644
--- a/config-default.yml
+++ b/config-default.yml
@@ -1,3 +1,6 @@
+debug: !ENV ["BOT_DEBUG", "true"]
+
+
bot:
prefix: "!"
sentry_dsn: !ENV "BOT_SENTRY_DSN"
diff --git a/tests/bot/exts/info/test_information.py b/tests/bot/exts/info/test_information.py
index 0aa41d889..d8250befb 100644
--- a/tests/bot/exts/info/test_information.py
+++ b/tests/bot/exts/info/test_information.py
@@ -507,7 +507,7 @@ class UserCommandTests(unittest.IsolatedAsyncioTestCase):
@unittest.mock.patch("bot.exts.info.information.Information.create_user_embed")
async def test_staff_members_can_bypass_channel_restriction(self, create_embed, constants):
"""Staff members should be able to bypass the bot-commands channel restriction."""
- constants.STAFF_ROLES = [self.moderator_role.id]
+ constants.STAFF_PARTNERS_COMMUNITY_ROLES = [self.moderator_role.id]
ctx = helpers.MockContext(author=self.moderator, channel=helpers.MockTextChannel(id=200))
await self.cog.user_info(self.cog, ctx)
@@ -519,7 +519,7 @@ class UserCommandTests(unittest.IsolatedAsyncioTestCase):
async def test_moderators_can_target_another_member(self, create_embed, constants):
"""A moderator should be able to use `!user` targeting another user."""
constants.MODERATION_ROLES = [self.moderator_role.id]
- constants.STAFF_ROLES = [self.moderator_role.id]
+ constants.STAFF_PARTNERS_COMMUNITY_ROLES = [self.moderator_role.id]
ctx = helpers.MockContext(author=self.moderator, channel=helpers.MockTextChannel(id=50))
await self.cog.user_info(self.cog, ctx, self.target)
diff --git a/tests/bot/rules/test_mentions.py b/tests/bot/rules/test_mentions.py
index 6444532f2..f8805ac48 100644
--- a/tests/bot/rules/test_mentions.py
+++ b/tests/bot/rules/test_mentions.py
@@ -2,12 +2,14 @@ from typing import Iterable
from bot.rules import mentions
from tests.bot.rules import DisallowedCase, RuleTest
-from tests.helpers import MockMessage
+from tests.helpers import MockMember, MockMessage
-def make_msg(author: str, total_mentions: int) -> MockMessage:
+def make_msg(author: str, total_user_mentions: int, total_bot_mentions: int = 0) -> MockMessage:
"""Makes a message with `total_mentions` mentions."""
- return MockMessage(author=author, mentions=list(range(total_mentions)))
+ user_mentions = [MockMember() for _ in range(total_user_mentions)]
+ bot_mentions = [MockMember(bot=True) for _ in range(total_bot_mentions)]
+ return MockMessage(author=author, mentions=user_mentions+bot_mentions)
class TestMentions(RuleTest):
@@ -48,11 +50,27 @@ class TestMentions(RuleTest):
[make_msg("bob", 2), make_msg("alice", 3), make_msg("bob", 2)],
("bob",),
4,
- )
+ ),
+ DisallowedCase(
+ [make_msg("bob", 3, 1)],
+ ("bob",),
+ 3,
+ ),
)
await self.run_disallowed(cases)
+ async def test_ignore_bot_mentions(self):
+ """Messages with an allowed amount of mentions, also containing bot mentions."""
+ cases = (
+ [make_msg("bob", 0, 3)],
+ [make_msg("bob", 2, 1)],
+ [make_msg("bob", 1, 2), make_msg("bob", 1, 2)],
+ [make_msg("bob", 1, 5), make_msg("alice", 2, 5)]
+ )
+
+ await self.run_allowed(cases)
+
def relevant_messages(self, case: DisallowedCase) -> Iterable[MockMessage]:
last_message = case.recent_messages[0]
return tuple(