Repository: python-discord/bot

Issue:
Have @Python add @everyone pings to checkpoint on a monthly basis
We've noticed that adding an @everyone message to the checkpoint channel every once in a while triggers a flood of users accepting our rules to gain the Developers role. Currently, those @everyone messages are added manually every once in a while, but it should be very straightforward to automate the process.

I would leave the current welcome message untouched, since it's a message from a human, but do it like this:

1. Remove previous @everyone message from @Python in that channel
2. Post message that says something like:
    - @everyone Please ping `@Admins` if you encounter any problems during the verification process.

I'm not sure what frequency is best for this. I wouldn't mind it once a month or even once a week. If people get bothered by it, they either accept and join for real or leave the server in some kind of self-purge (they've not accepted our rules anyway).


Discussion:
What do you think is the best approach to set this command? Adding a 

`asyncio.sleep(xxx)`
Does not seems a reliable to do so.
Probably the [tasks](https://discordpy.readthedocs.io/en/latest/ext/tasks/index.html) extension.
Though that may be problematic if the bot restarts... something could be stored in the database to keep track of the last time it was muted. I don't know how well that'd work with the tasks extension then. But we do have an API endpoint for storing miscellaneous settings in the database as key-value pairs (currently only used for DEFCON I believe).
Yes, basically using the tasks extension raise the same problems than using a simple sleep. 'll look at the API endpoint.
I don't know if there's a reason why we can't just have a short-circuit check of the timestamp of the existing message in the channel, in theory there's only ever going to be one message in the channel so iterating over the channel history to get it isn't going to be expensive.
Yes I think it will work. I’ll give it a try anyway, so I claim this issue for now.
That's alright, I'll assign the issue to you.

Meanwhile, I would like to see the message include something about how they haven't verified yet.

**How about this:**
`@everyone` To verify that you have read our rules, please type `!accept`. Ping `@Admins` if you encounter any problems during the verification process.

For frequency, I think weekly sounds about right.
I don't think they have any way of pinging admins, since they only have access to the verification channel and that channel removes all messages IIRC. They'd have to DM, wouldn't they?
We still get the notification, which alleviates the burdeon of the user searching for someone to DM, but it can be a pain to find it in the message logs.

It's probably beyond the scope of this PR, but providing a message for this ping in `#mod-logs` could be a useful enhancement.

Resolving patch:
diff --git a/bot/cogs/verification.py b/bot/cogs/verification.py
--- a/bot/cogs/verification.py
+++ b/bot/cogs/verification.py
@@ -1,10 +1,12 @@
 import logging
+from datetime import datetime
 
 from discord import Message, NotFound, Object
+from discord.ext import tasks
 from discord.ext.commands import Bot, Cog, Context, command
 
 from bot.cogs.moderation import ModLog
-from bot.constants import Channels, Event, Roles
+from bot.constants import Bot as BotConfig, Channels, Event, Roles
 from bot.decorators import InChannelCheckFailure, in_channel, without_role
 
 log = logging.getLogger(__name__)
@@ -27,12 +29,18 @@
 If you'd like to unsubscribe from the announcement notifications, simply send `!unsubscribe` to <#{Channels.bot}>.
 """
 
+PERIODIC_PING = (
+    f"@everyone To verify that you have read our rules, please type `{BotConfig.prefix}accept`."
+    f" Ping <@&{Roles.admin}> if you encounter any problems during the verification process."
+)
+
 
 class Verification(Cog):
     """User verification and role self-management."""
 
     def __init__(self, bot: Bot):
         self.bot = bot
+        self.periodic_ping.start()
 
     @property
     def mod_log(self) -> ModLog:
@@ -155,6 +163,34 @@ def bot_check(ctx: Context) -> bool:
         else:
             return True
 
+    @tasks.loop(hours=12)
+    async def periodic_ping(self) -> None:
+        """Every week, mention @everyone to remind them to verify."""
+        messages = self.bot.get_channel(Channels.verification).history(limit=10)
+        need_to_post = True  # True if a new message needs to be sent.
+
+        async for message in messages:
+            if message.author == self.bot.user and message.content == PERIODIC_PING:
+                delta = datetime.utcnow() - message.created_at  # Time since last message.
+                if delta.days >= 7:  # Message is older than a week.
+                    await message.delete()
+                else:
+                    need_to_post = False
+
+                break
+
+        if need_to_post:
+            await self.bot.get_channel(Channels.verification).send(PERIODIC_PING)
+
+    @periodic_ping.before_loop
+    async def before_ping(self) -> None:
+        """Only start the loop when the bot is ready."""
+        await self.bot.wait_until_ready()
+
+    def cog_unload(self) -> None:
+        """Cancel the periodic ping task when the cog is unloaded."""
+        self.periodic_ping.cancel()
+
 
 def setup(bot: Bot) -> None:
     """Verification cog load."""


Test patch: