aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bot/__init__.py6
-rw-r--r--bot/bot.py14
-rw-r--r--bot/cogs/antimalware.py12
-rw-r--r--bot/cogs/reminders.py2
-rw-r--r--bot/cogs/utils.py48
-rw-r--r--bot/constants.py7
-rw-r--r--config-default.yml3
7 files changed, 34 insertions, 58 deletions
diff --git a/bot/__init__.py b/bot/__init__.py
index 2dd4af225..4131b69e9 100644
--- a/bot/__init__.py
+++ b/bot/__init__.py
@@ -1,3 +1,4 @@
+import asyncio
import logging
import os
import sys
@@ -59,3 +60,8 @@ coloredlogs.install(logger=root_log, stream=sys.stdout)
logging.getLogger("discord").setLevel(logging.WARNING)
logging.getLogger("websockets").setLevel(logging.WARNING)
logging.getLogger(__name__)
+
+
+# On Windows, the selector event loop is required for aiodns.
+if os.name == "nt":
+ asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
diff --git a/bot/bot.py b/bot/bot.py
index 6dd5ba896..a85a22aa9 100644
--- a/bot/bot.py
+++ b/bot/bot.py
@@ -7,6 +7,7 @@ from typing import Optional
import aiohttp
import discord
from discord.ext import commands
+from sentry_sdk import push_scope
from bot import DEBUG_MODE, api, constants
from bot.async_stats import AsyncStatsClient
@@ -75,7 +76,7 @@ class Bot(commands.Bot):
await self._resolver.close()
if self.stats._transport:
- await self.stats._transport.close()
+ self.stats._transport.close()
async def login(self, *args, **kwargs) -> None:
"""Re-create the connector and set up sessions before logging into Discord."""
@@ -155,3 +156,14 @@ class Bot(commands.Bot):
gateway event before giving up and thus not populating the cache for unavailable guilds.
"""
await self._guild_available.wait()
+
+ async def on_error(self, event: str, *args, **kwargs) -> None:
+ """Log errors raised in event listeners rather than printing them to stderr."""
+ self.stats.incr(f"errors.event.{event}")
+
+ with push_scope() as scope:
+ scope.set_tag("event", event)
+ scope.set_extra("args", args)
+ scope.set_extra("kwargs", kwargs)
+
+ log.exception(f"Unhandled exception in {event}.")
diff --git a/bot/cogs/antimalware.py b/bot/cogs/antimalware.py
index 79bf486a4..66b5073e8 100644
--- a/bot/cogs/antimalware.py
+++ b/bot/cogs/antimalware.py
@@ -38,6 +38,18 @@ class AntiMalware(Cog):
"It looks like you tried to attach a Python file - "
f"please use a code-pasting service such as {URLs.site_schema}{URLs.site_paste}"
)
+ elif ".txt" in extensions_blocked:
+ # Work around Discord AutoConversion of messages longer than 2000 chars to .txt
+ cmd_channel = self.bot.get_channel(Channels.bot_commands)
+ embed.description = (
+ "**Uh-oh!** It looks like your message got zapped by our spam filter. "
+ "We currently don't allow `.txt` attachments, so here are some tips to help you travel safely: \n\n"
+ "• If you attempted to send a message longer than 2000 characters, try shortening your message "
+ "to fit within the character limit or use a pasting service (see below) \n\n"
+ "• If you tried to show someone your code, you can use codeblocks \n(run `!code-blocks` in "
+ f"{cmd_channel.mention} for more information) or use a pasting service like: "
+ f"\n\n{URLs.site_schema}{URLs.site_paste}"
+ )
elif extensions_blocked:
whitelisted_types = ', '.join(AntiMalwareConfig.whitelist)
meta_channel = self.bot.get_channel(Channels.meta)
diff --git a/bot/cogs/reminders.py b/bot/cogs/reminders.py
index 24c279357..8b6457cbb 100644
--- a/bot/cogs/reminders.py
+++ b/bot/cogs/reminders.py
@@ -158,7 +158,7 @@ class Reminders(Scheduler, Cog):
)
await self._delete_reminder(reminder["id"])
- @group(name="remind", aliases=("reminder", "reminders"), invoke_without_command=True)
+ @group(name="remind", aliases=("reminder", "reminders", "remindme"), invoke_without_command=True)
async def remind_group(self, ctx: Context, expiration: Duration, *, content: str) -> None:
"""Commands for managing your reminders."""
await ctx.invoke(self.new_reminder, expiration=expiration, content=content)
diff --git a/bot/cogs/utils.py b/bot/cogs/utils.py
index 8023eb962..89d556f58 100644
--- a/bot/cogs/utils.py
+++ b/bot/cogs/utils.py
@@ -2,19 +2,16 @@ import difflib
import logging
import re
import unicodedata
-from asyncio import TimeoutError, sleep
from email.parser import HeaderParser
from io import StringIO
from typing import Tuple, Union
-from dateutil import relativedelta
-from discord import Colour, Embed, Message, Role
+from discord import Colour, Embed
from discord.ext.commands import BadArgument, Cog, Context, command
from bot.bot import Bot
-from bot.constants import Channels, MODERATION_ROLES, Mention, STAFF_ROLES
+from bot.constants import Channels, MODERATION_ROLES, STAFF_ROLES
from bot.decorators import in_whitelist, with_role
-from bot.utils.time import humanize_delta
log = logging.getLogger(__name__)
@@ -162,47 +159,6 @@ class Utils(Cog):
await ctx.send(embed=embed)
@command()
- @with_role(*MODERATION_ROLES)
- async def mention(self, ctx: Context, *, role: Role) -> None:
- """Set a role to be mentionable for a limited time."""
- if role.mentionable:
- await ctx.send(f"{role} is already mentionable!")
- return
-
- await role.edit(reason=f"Role unlocked by {ctx.author}", mentionable=True)
-
- human_time = humanize_delta(relativedelta.relativedelta(seconds=Mention.message_timeout))
- await ctx.send(
- f"{role} has been made mentionable. I will reset it in {human_time}, or when someone mentions this role."
- )
-
- def check(m: Message) -> bool:
- """Checks that the message contains the role mention."""
- return role in m.role_mentions
-
- try:
- msg = await self.bot.wait_for("message", check=check, timeout=Mention.message_timeout)
- except TimeoutError:
- await role.edit(mentionable=False, reason="Automatic role lock - timeout.")
- await ctx.send(f"{ctx.author.mention}, you took too long. I have reset {role} to be unmentionable.")
- return
-
- if any(r.id in MODERATION_ROLES for r in msg.author.roles):
- await sleep(Mention.reset_delay)
- await role.edit(mentionable=False, reason=f"Automatic role lock by {msg.author}")
- await ctx.send(
- f"{ctx.author.mention}, I have reset {role} to be unmentionable as "
- f"{msg.author if msg.author != ctx.author else 'you'} sent a message mentioning it."
- )
- return
-
- await role.edit(mentionable=False, reason=f"Automatic role lock - unauthorised use by {msg.author}")
- await ctx.send(
- f"{ctx.author.mention}, I have reset {role} to be unmentionable "
- f"as I detected unauthorised use by {msg.author} (ID: {msg.author.id})."
- )
-
- @command()
async def zen(self, ctx: Context, *, search_value: Union[int, str, None] = None) -> None:
"""
Show the Zen of Python.
diff --git a/bot/constants.py b/bot/constants.py
index a00b59505..da29125eb 100644
--- a/bot/constants.py
+++ b/bot/constants.py
@@ -550,13 +550,6 @@ class HelpChannels(metaclass=YAMLGetter):
notify_roles: List[int]
-class Mention(metaclass=YAMLGetter):
- section = 'mention'
-
- message_timeout: int
- reset_delay: int
-
-
class RedirectOutput(metaclass=YAMLGetter):
section = 'redirect_output'
diff --git a/config-default.yml b/config-default.yml
index 78a2ff853..ff6790423 100644
--- a/config-default.yml
+++ b/config-default.yml
@@ -507,9 +507,6 @@ free:
cooldown_rate: 1
cooldown_per: 60.0
-mention:
- message_timeout: 300
- reset_delay: 5
help_channels:
enable: true