diff options
Diffstat (limited to 'bot/exts/backend')
| -rw-r--r-- | bot/exts/backend/error_handler.py | 10 | ||||
| -rw-r--r-- | bot/exts/backend/sync/_cog.py | 9 | ||||
| -rw-r--r-- | bot/exts/backend/sync/_syncers.py | 66 |
3 files changed, 44 insertions, 41 deletions
diff --git a/bot/exts/backend/error_handler.py b/bot/exts/backend/error_handler.py index c643d346e..5b5840858 100644 --- a/bot/exts/backend/error_handler.py +++ b/bot/exts/backend/error_handler.py @@ -8,7 +8,7 @@ from sentry_sdk import push_scope from bot.api import ResponseCodeError from bot.bot import Bot -from bot.constants import Channels, Colours +from bot.constants import Colours from bot.converters import TagNameConverter from bot.errors import LockedResourceError from bot.utils.checks import InWhitelistCheckFailure @@ -47,7 +47,6 @@ class ErrorHandler(Cog): * If CommandNotFound is raised when invoking the tag (determined by the presence of the `invoked_from_error_handler` attribute), this error is treated as being unexpected and therefore sends an error message - * Commands in the verification channel are ignored 2. UserInputError: see `handle_user_input_error` 3. CheckFailure: see `handle_check_failure` 4. CommandOnCooldown: send an error message in the invoking context @@ -63,10 +62,9 @@ class ErrorHandler(Cog): if isinstance(e, errors.CommandNotFound) and not hasattr(ctx, "invoked_from_error_handler"): if await self.try_silence(ctx): return - if ctx.channel.id != Channels.verification: - # Try to look for a tag with the command's name - await self.try_get_tag(ctx) - return # Exit early to avoid logging. + # Try to look for a tag with the command's name + await self.try_get_tag(ctx) + return # Exit early to avoid logging. elif isinstance(e, errors.UserInputError): await self.handle_user_input_error(ctx, e) elif isinstance(e, errors.CheckFailure): diff --git a/bot/exts/backend/sync/_cog.py b/bot/exts/backend/sync/_cog.py index 6e85e2b7d..48d2b6f02 100644 --- a/bot/exts/backend/sync/_cog.py +++ b/bot/exts/backend/sync/_cog.py @@ -18,9 +18,6 @@ class Sync(Cog): def __init__(self, bot: Bot) -> None: self.bot = bot - self.role_syncer = _syncers.RoleSyncer(self.bot) - self.user_syncer = _syncers.UserSyncer(self.bot) - self.bot.loop.create_task(self.sync_guild()) async def sync_guild(self) -> None: @@ -31,7 +28,7 @@ class Sync(Cog): if guild is None: return - for syncer in (self.role_syncer, self.user_syncer): + for syncer in (_syncers.RoleSyncer, _syncers.UserSyncer): await syncer.sync(guild) async def patch_user(self, user_id: int, json: Dict[str, Any], ignore_404: bool = False) -> None: @@ -171,10 +168,10 @@ class Sync(Cog): @commands.has_permissions(administrator=True) async def sync_roles_command(self, ctx: Context) -> None: """Manually synchronise the guild's roles with the roles on the site.""" - await self.role_syncer.sync(ctx.guild, ctx) + await _syncers.RoleSyncer.sync(ctx.guild, ctx) @sync_group.command(name='users') @commands.has_permissions(administrator=True) async def sync_users_command(self, ctx: Context) -> None: """Manually synchronise the guild's users with the users on the site.""" - await self.user_syncer.sync(ctx.guild, ctx) + await _syncers.UserSyncer.sync(ctx.guild, ctx) diff --git a/bot/exts/backend/sync/_syncers.py b/bot/exts/backend/sync/_syncers.py index 38468c2b1..2eb9f9971 100644 --- a/bot/exts/backend/sync/_syncers.py +++ b/bot/exts/backend/sync/_syncers.py @@ -6,8 +6,8 @@ from collections import namedtuple from discord import Guild from discord.ext.commands import Context +import bot from bot.api import ResponseCodeError -from bot.bot import Bot log = logging.getLogger(__name__) @@ -17,57 +17,60 @@ _Role = namedtuple('Role', ('id', 'name', 'colour', 'permissions', 'position')) _Diff = namedtuple('Diff', ('created', 'updated', 'deleted')) +# Implementation of static abstract methods are not enforced if the subclass is never instantiated. +# However, methods are kept abstract to at least symbolise that they should be abstract. class Syncer(abc.ABC): """Base class for synchronising the database with objects in the Discord cache.""" - def __init__(self, bot: Bot) -> None: - self.bot = bot - + @staticmethod @property @abc.abstractmethod - def name(self) -> str: + def name() -> str: """The name of the syncer; used in output messages and logging.""" raise NotImplementedError # pragma: no cover + @staticmethod @abc.abstractmethod - async def _get_diff(self, guild: Guild) -> _Diff: + async def _get_diff(guild: Guild) -> _Diff: """Return the difference between the cache of `guild` and the database.""" raise NotImplementedError # pragma: no cover + @staticmethod @abc.abstractmethod - async def _sync(self, diff: _Diff) -> None: + async def _sync(diff: _Diff) -> None: """Perform the API calls for synchronisation.""" raise NotImplementedError # pragma: no cover - async def sync(self, guild: Guild, ctx: t.Optional[Context] = None) -> None: + @classmethod + async def sync(cls, guild: Guild, ctx: t.Optional[Context] = None) -> None: """ Synchronise the database with the cache of `guild`. If `ctx` is given, send a message with the results. """ - log.info(f"Starting {self.name} syncer.") + log.info(f"Starting {cls.name} syncer.") if ctx: - message = await ctx.send(f"📊 Synchronising {self.name}s.") + message = await ctx.send(f"📊 Synchronising {cls.name}s.") else: message = None - diff = await self._get_diff(guild) + diff = await cls._get_diff(guild) try: - await self._sync(diff) + await cls._sync(diff) except ResponseCodeError as e: - log.exception(f"{self.name} syncer failed!") + log.exception(f"{cls.name} syncer failed!") # Don't show response text because it's probably some really long HTML. results = f"status {e.status}\n```{e.response_json or 'See log output for details'}```" - content = f":x: Synchronisation of {self.name}s failed: {results}" + content = f":x: Synchronisation of {cls.name}s failed: {results}" else: diff_dict = diff._asdict() results = (f"{name} `{len(val)}`" for name, val in diff_dict.items() if val is not None) results = ", ".join(results) - log.info(f"{self.name} syncer finished: {results}.") - content = f":ok_hand: Synchronisation of {self.name}s complete: {results}" + log.info(f"{cls.name} syncer finished: {results}.") + content = f":ok_hand: Synchronisation of {cls.name}s complete: {results}" if message: await message.edit(content=content) @@ -78,10 +81,11 @@ class RoleSyncer(Syncer): name = "role" - async def _get_diff(self, guild: Guild) -> _Diff: + @staticmethod + async def _get_diff(guild: Guild) -> _Diff: """Return the difference of roles between the cache of `guild` and the database.""" log.trace("Getting the diff for roles.") - roles = await self.bot.api_client.get('bot/roles') + roles = await bot.instance.api_client.get('bot/roles') # Pack DB roles and guild roles into one common, hashable format. # They're hashable so that they're easily comparable with sets later. @@ -110,19 +114,20 @@ class RoleSyncer(Syncer): return _Diff(roles_to_create, roles_to_update, roles_to_delete) - async def _sync(self, diff: _Diff) -> None: + @staticmethod + async def _sync(diff: _Diff) -> None: """Synchronise the database with the role cache of `guild`.""" log.trace("Syncing created roles...") for role in diff.created: - await self.bot.api_client.post('bot/roles', json=role._asdict()) + await bot.instance.api_client.post('bot/roles', json=role._asdict()) log.trace("Syncing updated roles...") for role in diff.updated: - await self.bot.api_client.put(f'bot/roles/{role.id}', json=role._asdict()) + await bot.instance.api_client.put(f'bot/roles/{role.id}', json=role._asdict()) log.trace("Syncing deleted roles...") for role in diff.deleted: - await self.bot.api_client.delete(f'bot/roles/{role.id}') + await bot.instance.api_client.delete(f'bot/roles/{role.id}') class UserSyncer(Syncer): @@ -130,7 +135,8 @@ class UserSyncer(Syncer): name = "user" - async def _get_diff(self, guild: Guild) -> _Diff: + @staticmethod + async def _get_diff(guild: Guild) -> _Diff: """Return the difference of users between the cache of `guild` and the database.""" log.trace("Getting the diff for users.") @@ -138,7 +144,7 @@ class UserSyncer(Syncer): users_to_update = [] seen_guild_users = set() - async for db_user in self._get_users(): + async for db_user in UserSyncer._get_users(): # Store user fields which are to be updated. updated_fields = {} @@ -185,24 +191,26 @@ class UserSyncer(Syncer): return _Diff(users_to_create, users_to_update, None) - async def _get_users(self) -> t.AsyncIterable: + @staticmethod + async def _get_users() -> t.AsyncIterable: """GET users from database.""" query_params = { "page": 1 } while query_params["page"]: - res = await self.bot.api_client.get("bot/users", params=query_params) + res = await bot.instance.api_client.get("bot/users", params=query_params) for user in res["results"]: yield user query_params["page"] = res["next_page_no"] - async def _sync(self, diff: _Diff) -> None: + @staticmethod + async def _sync(diff: _Diff) -> None: """Synchronise the database with the user cache of `guild`.""" log.trace("Syncing created users...") if diff.created: - await self.bot.api_client.post("bot/users", json=diff.created) + await bot.instance.api_client.post("bot/users", json=diff.created) log.trace("Syncing updated users...") if diff.updated: - await self.bot.api_client.patch("bot/users/bulk_patch", json=diff.updated) + await bot.instance.api_client.patch("bot/users/bulk_patch", json=diff.updated) |