diff options
-rw-r--r-- | bot/errors.py | 2 | ||||
-rw-r--r-- | bot/exts/backend/branding/_cog.py | 34 | ||||
-rw-r--r-- | bot/exts/backend/branding/_repository.py | 30 |
3 files changed, 37 insertions, 29 deletions
diff --git a/bot/errors.py b/bot/errors.py index 7949dc1b4..31d264686 100644 --- a/bot/errors.py +++ b/bot/errors.py @@ -59,7 +59,7 @@ class InvalidInfractionError(ConversionError): class BrandingMisconfigurationError(RuntimeError): - """Raised by the Branding cog when a misconfigured event is encountered.""" + """Raised by the Branding cog when branding misconfiguration is detected.""" diff --git a/bot/exts/backend/branding/_cog.py b/bot/exts/backend/branding/_cog.py index 433f152b4..40c2c2c6f 100644 --- a/bot/exts/backend/branding/_cog.py +++ b/bot/exts/backend/branding/_cog.py @@ -342,14 +342,14 @@ class Branding(commands.Cog): """ log.debug("Synchronise: fetching current event.") - current_event, available_events = await self.repository.get_current_event() + try: + current_event, available_events = await self.repository.get_current_event() + except Exception: + log.exception("Synchronisation aborted: failed to fetch events.") + return False, False await self.populate_cache_events(available_events) - if current_event is None: - log.error("Failed to fetch event. Cannot synchronise!") - return False, False - return await self.enter_event(current_event) async def populate_cache_events(self, events: list[Event]) -> None: @@ -433,10 +433,6 @@ class Branding(commands.Cog): await self.populate_cache_events(available_events) - if new_event is None: - log.warning("Daemon main: failed to get current event from branding repository, will do nothing.") - return - if new_event.path != await self.cache_information.get("event_path"): log.debug("Daemon main: new event detected!") await self.enter_event(new_event) @@ -596,8 +592,24 @@ class Branding(commands.Cog): log.info("Performing command-requested event cache refresh.") async with ctx.typing(): - available_events = await self.repository.get_events() - await self.populate_cache_events(available_events) + try: + available_events = await self.repository.get_events() + except Exception: + log.exception("Refresh aborted: failed to fetch events.") + resp = make_embed( + "Refresh aborted", + "Failed to fetch events. See log for details.", + success=False, + ) + else: + await self.populate_cache_events(available_events) + resp = make_embed( + "Refresh successful", + "The event calendar has been refreshed.", + success=True, + ) + + await ctx.send(embed=resp) await ctx.invoke(self.branding_calendar_group) diff --git a/bot/exts/backend/branding/_repository.py b/bot/exts/backend/branding/_repository.py index 20cad0a5d..7d2de9bf2 100644 --- a/bot/exts/backend/branding/_repository.py +++ b/bot/exts/backend/branding/_repository.py @@ -186,37 +186,34 @@ class BrandingRepository: """ Discover available events in the branding repository. - Misconfigured events are skipped. May return an empty list in the catastrophic case. + Propagate errors if an event fails to fetch or deserialize. """ log.debug("Discovering events in branding repository.") - try: - event_directories = await self.fetch_directory("events", types=("dir",)) # Skip files. - except Exception: - log.exception("Failed to fetch 'events' directory.") - return [] + event_directories = await self.fetch_directory("events", types=("dir",)) # Skip files. instances: list[Event] = [] for event_directory in event_directories.values(): - log.trace(f"Attempting to construct event from directory: '{event_directory.path}'.") - try: - instance = await self.construct_event(event_directory) - except Exception as exc: - log.warning(f"Could not construct event '{event_directory.path}'.", exc_info=exc) - else: - instances.append(instance) + log.trace(f"Reading event directory: '{event_directory.path}'.") + instance = await self.construct_event(event_directory) + instances.append(instance) return instances - async def get_current_event(self) -> tuple[Event | None, list[Event]]: + async def get_current_event(self) -> tuple[Event, list[Event]]: """ Get the currently active event, or the fallback event. The second return value is a list of all available events. The caller may discard it, if not needed. Returning all events alongside the current one prevents having to query the API twice in some cases. - The current event may be None in the case that no event is active, and no fallback event is found. + Raise an error in the following cases: + * GitHub request fails + * The branding repo contains an invalid event + * No event is active and the fallback event is missing + + Events are validated in the branding repo. The bot assumes that events are valid. """ utc_now = datetime.now(tz=UTC) log.debug(f"Finding active event for: {utc_now}.") @@ -249,5 +246,4 @@ class BrandingRepository: if event.meta.is_fallback: return event, available_events - log.warning("No event is currently active and no fallback event was found!") - return None, available_events + raise BrandingMisconfigurationError("No event is active and the fallback event is missing!") |