From ec262d4c306dce9249d499370676455922ac8d45 Mon Sep 17 00:00:00 2001 From: Michael H Date: Mon, 20 Jul 2020 13:51:27 -0400 Subject: [PATCH] [Announcer] Don't die with a lack of channels (#4089) --- redbot/cogs/admin/admin.py | 61 +++++++++++++++++++++++----------- redbot/cogs/admin/announcer.py | 31 ++++++----------- 2 files changed, 52 insertions(+), 40 deletions(-) diff --git a/redbot/cogs/admin/admin.py b/redbot/cogs/admin/admin.py index 80fad1587..8de74a4d0 100644 --- a/redbot/cogs/admin/admin.py +++ b/redbot/cogs/admin/admin.py @@ -1,3 +1,4 @@ +import asyncio import logging from typing import Tuple @@ -72,15 +73,45 @@ class Admin(commands.Cog): def __init__(self): self.config = Config.get_conf(self, 8237492837454039, force_registration=True) - self.config.register_global(serverlocked=False) + self.config.register_global(serverlocked=False, schema_version=0) self.config.register_guild( - announce_ignore=False, - announce_channel=None, # Integer ID - selfroles=[], # List of integer ID's + announce_channel=None, selfroles=[], # Integer ID # List of integer ID's ) self.__current_announcer = None + self._ready = asyncio.Event() + asyncio.create_task(self.handle_migrations()) + # As this is a data migration, don't store this for cancelation. + + async def cog_before_invoke(self): + await self._ready.wait() + + async def handle_migrations(self): + + lock = self.config.get_guilds_lock() + async with lock: + # This prevents the edge case of someone loading admin, + # unloading it, loading it again during a migration + current_schema = await self.config.schema_version() + + if current_schema == 0: + await self.migrate_config_from_0_to_1() + await self.config.schema_version.set(1) + + await self._ready.set() + + async def migrate_config_from_0_to_1(self): + + all_guilds = await self.config.all_guilds() + + for guild_id, guild_data in all_guilds.items(): + if guild_data.get("announce_ignore", False): + async with self.config.guild_from_id(guild_id).all( + acquire_lock=False + ) as guild_config: + guild_config.pop("announce_channel", None) + guild_config.pop("announce_ignore", None) def cog_unload(self): try: @@ -320,7 +351,7 @@ class Admin(commands.Cog): async def announceset_channel(self, ctx, *, channel: discord.TextChannel = None): """ Change the channel where the bot will send announcements. - + If channel is left blank it defaults to the current channel. """ if channel is None: @@ -330,21 +361,11 @@ class Admin(commands.Cog): _("The announcement channel has been set to {channel.mention}").format(channel=channel) ) - @announceset.command(name="ignore") - async def announceset_ignore(self, ctx): - """Toggle announcements being enabled this server.""" - ignored = await self.config.guild(ctx.guild).announce_ignore() - await self.config.guild(ctx.guild).announce_ignore.set(not ignored) - if ignored: - await ctx.send( - _("The server {guild.name} will receive announcements.").format(guild=ctx.guild) - ) - else: - await ctx.send( - _("The server {guild.name} will not receive announcements.").format( - guild=ctx.guild - ) - ) + @announceset.command(name="clearchannel") + async def announceset_clear_channel(self, ctx): + """Unsets the channel for announcements.""" + await self.config.guild(ctx.guild).announce_channel.clear() + await ctx.tick() async def _valid_selfroles(self, guild: discord.Guild) -> Tuple[discord.Role]: """ diff --git a/redbot/cogs/admin/announcer.py b/redbot/cogs/admin/announcer.py index 1485f5109..3e63cda54 100644 --- a/redbot/cogs/admin/announcer.py +++ b/redbot/cogs/admin/announcer.py @@ -1,4 +1,5 @@ import asyncio +from typing import Optional import discord from redbot.core import commands @@ -38,20 +39,9 @@ class Announcer: """ self.active = False - async def _get_announce_channel(self, guild: discord.Guild) -> discord.TextChannel: + async def _get_announce_channel(self, guild: discord.Guild) -> Optional[discord.TextChannel]: channel_id = await self.config.guild(guild).announce_channel() - channel = None - - if channel_id is not None: - channel = guild.get_channel(channel_id) - - if channel is None: - channel = guild.system_channel - - if channel is None: - channel = guild.text_channels[0] - - return channel + return guild.get_channel(channel_id) async def announcer(self): guild_list = self.ctx.bot.guilds @@ -60,15 +50,16 @@ class Announcer: if not self.active: return - if await self.config.guild(g).announce_ignore(): - continue - channel = await self._get_announce_channel(g) - try: - await channel.send(self.message) - except discord.Forbidden: - failed.append(str(g.id)) + if channel: + if channel.permissions_for(g.me).send_messages: + try: + await channel.send(self.message) + except discord.Forbidden: + failed.append(str(g.id)) + else: + failed.append(str(g.id)) if failed: msg = (