feat(schedule): Add DM notifications.
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
from random import random
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
import datetime as dt
|
import datetime as dt
|
||||||
import asyncio
|
import asyncio
|
||||||
@@ -335,12 +336,12 @@ class ScheduledSession:
|
|||||||
self.opened = True
|
self.opened = True
|
||||||
|
|
||||||
@log_wrap(action='Notify')
|
@log_wrap(action='Notify')
|
||||||
async def _notify(self, wait=60):
|
async def _notify(self, ping_wait=10, dm_wait=60):
|
||||||
"""
|
"""
|
||||||
Ghost ping members who have not yet attended.
|
Ghost ping members who have not yet attended.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
await asyncio.sleep(wait)
|
await asyncio.sleep(ping_wait)
|
||||||
except asyncio.CancelledError:
|
except asyncio.CancelledError:
|
||||||
return
|
return
|
||||||
missing = [mid for mid, m in self.members.items() if m.total_clock == 0 and m.clock_start is None]
|
missing = [mid for mid, m in self.members.items() if m.total_clock == 0 and m.clock_start is None]
|
||||||
@@ -349,6 +350,90 @@ class ScheduledSession:
|
|||||||
message = await self.send(ping)
|
message = await self.send(ping)
|
||||||
if message is not None:
|
if message is not None:
|
||||||
asyncio.create_task(message.delete())
|
asyncio.create_task(message.delete())
|
||||||
|
try:
|
||||||
|
# Random dither to spread out sharded notifications
|
||||||
|
dither = 30 * random()
|
||||||
|
await asyncio.sleep(dm_wait - ping_wait + dither)
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
return
|
||||||
|
|
||||||
|
if not self.guild:
|
||||||
|
# In case we somehow left the guild in the meantime
|
||||||
|
return
|
||||||
|
|
||||||
|
missing = [mid for mid, m in self.members.items() if m.total_clock == 0 and m.clock_start is None]
|
||||||
|
for mid in missing:
|
||||||
|
member = self.guild.get_member(mid)
|
||||||
|
if member:
|
||||||
|
args = await self._notify_dm(member)
|
||||||
|
try:
|
||||||
|
await member.send(**args.send_args)
|
||||||
|
except discord.HTTPException:
|
||||||
|
# Discord really doesn't like failed DM requests
|
||||||
|
# So take a moment of silence
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
|
async def _notify_dm(self, member: discord.Member) -> MessageArgs:
|
||||||
|
t = self.bot.translator.t
|
||||||
|
# Join line depends on guild setup
|
||||||
|
channels = self.channels_setting.value
|
||||||
|
room = self.room_channel
|
||||||
|
if room:
|
||||||
|
if room.type is discord.enums.ChannelType.category:
|
||||||
|
join_line = t(_p(
|
||||||
|
'session|notify|dm|join_line:room_category',
|
||||||
|
"Please attend your session by joining a voice channel under **{room}**!"
|
||||||
|
)).format(room=room.name)
|
||||||
|
else:
|
||||||
|
join_line = t(_p(
|
||||||
|
'session|notify|dm|join_line:room_voice',
|
||||||
|
"Please attend your session by joining {room}"
|
||||||
|
)).format(room=room.mention)
|
||||||
|
elif not channels:
|
||||||
|
join_line = t(_p(
|
||||||
|
'session|notify|dm|join_line:all_channels',
|
||||||
|
"Please attend your session by joining a tracked voice channel!"
|
||||||
|
))
|
||||||
|
else:
|
||||||
|
# Expand channels into a list of valid voice channels
|
||||||
|
voice_channels = set()
|
||||||
|
for channel in channels:
|
||||||
|
if channel.type is discord.enums.ChannelType.category:
|
||||||
|
voice_channels.update(channel.voice_channels)
|
||||||
|
elif channel.type is discord.enums.ChannelType.voice:
|
||||||
|
voice_channels.add(channel)
|
||||||
|
|
||||||
|
# Now filter by connectivity and tracked
|
||||||
|
voice_tracker = self.bot.get_cog('VoiceTrackerCog')
|
||||||
|
valid = []
|
||||||
|
for channel in voice_channels:
|
||||||
|
if voice_tracker.is_untracked(channel):
|
||||||
|
continue
|
||||||
|
if not channel.permissions_for(member).connect:
|
||||||
|
continue
|
||||||
|
valid.append(channel)
|
||||||
|
join_line = t(_p(
|
||||||
|
'session|notify|dm|join_line:channels',
|
||||||
|
"Please attend your session by joining one of the following:"
|
||||||
|
))
|
||||||
|
join_line = '\n'.join(join_line, *(channel.mention for channel in valid[:20]))
|
||||||
|
if len(valid) > 20:
|
||||||
|
join_line += '\n...'
|
||||||
|
|
||||||
|
embed = discord.Embed(
|
||||||
|
colour=discord.Colour.orange(),
|
||||||
|
title=t(_p(
|
||||||
|
'session|notify|dm|title',
|
||||||
|
"Your Scheduled Session has started!"
|
||||||
|
)),
|
||||||
|
description=t(_p(
|
||||||
|
'session|notify|dm|description',
|
||||||
|
"Your scheduled session in {dest} has now begun!"
|
||||||
|
)).format(
|
||||||
|
dest=self.lobby_channel.mention if self.lobby_channel else f"**{self.guild.name}**"
|
||||||
|
) + '\n' + join_line
|
||||||
|
)
|
||||||
|
return MessageArgs(embed=embed)
|
||||||
|
|
||||||
def notify(self):
|
def notify(self):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -79,6 +79,18 @@ class VoiceTrackerCog(LionCog):
|
|||||||
"""
|
"""
|
||||||
return VoiceSession.get(self.bot, guildid, userid, **kwargs)
|
return VoiceSession.get(self.bot, guildid, userid, **kwargs)
|
||||||
|
|
||||||
|
def is_untracked(self, channel) -> bool:
|
||||||
|
if not channel.guild:
|
||||||
|
raise ValueError("Untracked check invalid for private channels.")
|
||||||
|
untracked = self.untracked_channels.get(channel.guild.id, ())
|
||||||
|
if channel.id in untracked:
|
||||||
|
untracked = True
|
||||||
|
elif channel.category_id and channel.category_id in untracked:
|
||||||
|
untracked = True
|
||||||
|
else:
|
||||||
|
untracked = False
|
||||||
|
return untracked
|
||||||
|
|
||||||
@LionCog.listener('on_ready')
|
@LionCog.listener('on_ready')
|
||||||
@log_wrap(action='Init Voice Sessions')
|
@log_wrap(action='Init Voice Sessions')
|
||||||
async def initialise(self):
|
async def initialise(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user