Merge pull request #2 from StudyLions/staging

Bugfixes and small UI updates
This commit is contained in:
Interitio
2021-10-20 09:24:30 +03:00
committed by GitHub
7 changed files with 78 additions and 40 deletions

View File

@@ -46,11 +46,12 @@ async def preload_guild_configuration(client):
Loads the plain guild configuration for all guilds the client is part of into data.
"""
guildids = [guild.id for guild in client.guilds]
rows = client.data.guild_config.fetch_rows_where(guildid=guildids)
client.log(
"Preloaded guild configuration for {} guilds.".format(len(rows)),
context="CORE_LOADING"
)
if guildids:
rows = client.data.guild_config.fetch_rows_where(guildid=guildids)
client.log(
"Preloaded guild configuration for {} guilds.".format(len(rows)),
context="CORE_LOADING"
)
@module.launch_task
@@ -59,11 +60,12 @@ async def preload_studying_members(client):
Loads the member data for all members who are currently in voice channels.
"""
userids = list(set(member.id for guild in client.guilds for ch in guild.voice_channels for member in ch.members))
rows = client.data.lions.fetch_rows_where(userid=userids)
client.log(
"Preloaded member data for {} members.".format(len(rows)),
context="CORE_LOADING"
)
if userids:
rows = client.data.lions.fetch_rows_where(userid=userids)
client.log(
"Preloaded member data for {} members.".format(len(rows)),
context="CORE_LOADING"
)
@module.launch_task

View File

@@ -72,6 +72,9 @@ class TimeSlot:
connect=False
)
happy_lion = "https://media.discordapp.net/stickers/898266283559227422.png"
sad_lion = "https://media.discordapp.net/stickers/898266548421148723.png"
def __init__(self, guild, start_time, data=None):
self.guild: discord.Guild = guild
self.start_time: datetime.datetime = start_time
@@ -139,13 +142,16 @@ class TimeSlot:
else:
classifications["Attended"].append(mention)
all_attended = all(mem.has_attended for mem in self.members.values())
bonus_line = (
"{tick} All members attended, and will get a `{bonus} LC` completion bonus!".format(
"{tick} Everyone attended, and will get a `{bonus} LC` bonus!".format(
tick=tick,
bonus=GuildSettings(self.guild.id).accountability_bonus.value
)
if all(mem.has_attended for mem in self.members.values()) else ""
if all_attended else ""
)
if all_attended:
embed.set_thumbnail(url=self.happy_lion)
embed.description += "\n" + bonus_line
for field, value in classifications.items():
@@ -182,16 +188,22 @@ class TimeSlot:
else:
classifications["Missing"].append(mention)
all_attended = all(mem.has_attended for mem in self.members.values())
bonus_line = (
"{tick} All members attended, and received a `{bonus} LC` completion bonus!".format(
"{tick} Everyone attended, and received a `{bonus} LC` bonus!".format(
tick=tick,
bonus=GuildSettings(self.guild.id).accountability_bonus.value
)
if all(mem.has_attended for mem in self.members.values()) else
if all_attended else
"{cross} Some members missed the session, so everyone missed out on the bonus!".format(
cross=cross
)
)
if all_attended:
embed.set_thumbnail(url=self.happy_lion)
else:
embed.set_thumbnail(url=self.sad_lion)
embed.description += "\n" + bonus_line
for field, value in classifications.items():
@@ -292,7 +304,7 @@ class TimeSlot:
self.message = await self.lobby.send(
embed=self.open_embed
)
except discord.HTTPException as e:
except discord.HTTPException:
GuildSettings(self.guild.id).event_log.log(
"Failed to post the status message in the accountability lobby {}.\n"
"Skipping this session.".format(self.lobby.mention),
@@ -322,10 +334,21 @@ class TimeSlot:
Update the status message, and launch the DM reminder.
"""
if self.channel:
await self.channel.edit(name="Accountability Study Room")
await self.channel.set_permissions(self.guild.default_role, view_channel=True, connect=False)
try:
await self.channel.edit(name="Accountability Study Room")
await self.channel.set_permissions(self.guild.default_role, view_channel=True, connect=False)
except discord.HTTPException:
pass
asyncio.create_task(self.dm_reminder(delay=60))
await self.message.edit(embed=self.status_embed)
try:
await self.message.edit(embed=self.status_embed)
except discord.NotFound:
try:
self.message = await self.lobby.send(
embed=self.status_embed
)
except discord.HTTPException:
self.message = None
async def dm_reminder(self, delay=60):
"""

View File

@@ -232,7 +232,8 @@ async def turnover():
# Start all the current rooms
await asyncio.gather(
*(slot.start() for slot in current_slots)
*(slot.start() for slot in current_slots),
return_exceptions=True
)

View File

@@ -353,9 +353,10 @@ class Ticket:
Method used to revert the ticket action, e.g. unban or remove mute role.
Generally called by `pardon` and `_expire`.
Must be overriden by the Ticket type, if they implement any revert logic.
May be overriden by the Ticket type, if they implement any revert logic.
Is a no-op by default.
"""
raise NotImplementedError
return
async def _expire(self):
"""

View File

@@ -87,9 +87,9 @@ class video_studyban(settings.Boolean, GuildSetting):
@property
def success_response(self):
if self.value:
"Members will now be study banned if they don't enable their video in the configured video channels."
return "Members will now be study-banned if they don't enable their video in the configured video channels."
else:
"Members will not be studybanned if they don't enable their video in video channels."
return "Members will not be study-banned if they don't enable their video in video channels."
@GuildSettings.attach_setting

View File

@@ -265,6 +265,13 @@ async def cmd_studybadges(ctx, flags):
# Parse the input
lines = ctx.args.splitlines()
results = [await parse_level(ctx, line) for line in lines]
# Check for duplicates
_set = set()
duplicate = next((time for time, _ in results if time in _set or _set.add(time)), None)
if duplicate:
return await ctx.error_reply(
"Level `{}` provided twice!".format(strfdur(duplicate, short=False))
)
current_times = set(row.required_time for row in guild_roles)
# Split up the provided lines into levels to add and levels to edit

View File

@@ -1,6 +1,5 @@
import json
import asyncio
import datetime
import itertools
from io import StringIO
from enum import IntEnum
@@ -12,7 +11,7 @@ from cmdClient.Context import Context
from cmdClient.lib import SafeCancellation
from meta import client
from utils.lib import parse_dur, strfdur, strfdelta, prop_tabulate, multiple_replace
from utils.lib import parse_dur, strfdur, prop_tabulate, multiple_replace
from .base import UserInputError
@@ -100,7 +99,7 @@ class Boolean(SettingType):
Looks up the provided string in the truthy and falsey tables.
"""
_userstr = userstr.lower()
if _userstr == "none":
if not _userstr or _userstr == "none":
return None
if _userstr in cls._truthy:
return True
@@ -154,7 +153,7 @@ class Integer(SettingType):
"""
Relies on integer casting to convert the user string
"""
if userstr.lower() == "none":
if not userstr or userstr.lower() == "none":
return None
try:
@@ -222,7 +221,7 @@ class String(SettingType):
Check that the user-entered string is of the correct length.
Accept "None" to unset.
"""
if userstr.lower() == "none":
if not userstr or userstr.lower() == "none":
# Unsetting case
return None
elif cls._maxlen is not None and len(userstr) > cls._maxlen:
@@ -284,7 +283,7 @@ class Channel(SettingType):
Pass to the channel seeker utility to find the requested channel.
Handle `0` and variants of `None` to unset.
"""
if userstr.lower() in ('0', 'none'):
if userstr.lower() in ('', '0', 'none'):
return None
else:
channel = await ctx.find_channel(userstr, interactive=True, chan_type=cls._chan_type)
@@ -296,13 +295,17 @@ class Channel(SettingType):
@classmethod
def _format_data(cls, id: int, data: Optional[int], **kwargs):
"""
Retrieve an artificially created channel mention.
If the channel does not exist, this will show up as invalid-channel.
Retrieve the channel mention, if the channel still exists.
If the channel no longer exists, or cannot be seen by the client, returns None.
"""
if data is None:
return None
else:
return "<#{}>".format(data)
channel = client.get_channel(data)
if channel:
return channel.mention
else:
return None
class VoiceChannel(Channel):
@@ -375,7 +378,7 @@ class Role(SettingType):
Pass to the role seeker utility to find the requested role.
Handle `0` and variants of `None` to unset.
"""
if userstr.lower() in ('0', 'none'):
if userstr.lower() in ('', '0', 'none'):
return None
else:
role = await ctx.find_role(userstr, create=cls._parse_create, interactive=True)
@@ -452,7 +455,7 @@ class Emoji(SettingType):
Pass to the emoji string parser to get the emoji.
Handle `0` and variants of `None` to unset.
"""
if userstr.lower() in ('0', 'none'):
if userstr.lower() in ('', '0', 'none'):
return None
else:
return cls._parse_emoji(userstr)
@@ -505,7 +508,7 @@ class Timezone(SettingType):
Check that the user-entered string is of the correct length.
Accept "None" to unset.
"""
if userstr.lower() == "none":
if not userstr or userstr.lower() == "none":
# Unsetting case
return None
try:
@@ -585,7 +588,7 @@ class IntegerEnum(SettingType):
options = {name.lower(): mem.value for name, mem in cls._enum.__members__.items()}
if userstr == "none":
if not userstr or userstr == "none":
# Unsetting case
return None
elif userstr not in options:
@@ -654,7 +657,7 @@ class Duration(SettingType):
"""
Parse the provided duration.
"""
if userstr.lower() == "none":
if not userstr or userstr.lower() == "none":
return None
if cls._default_multiplier and userstr.isdigit():
@@ -949,12 +952,13 @@ class SettingList(SettingType):
Splits the user string across `,` to break up the list.
Handle `0` and variants of `None` to unset.
"""
if userstr.lower() in ('0', 'none'):
if userstr.lower() in ('', '0', 'none'):
return []
else:
data = []
for item in userstr.split(','):
data.append(await cls._setting._parse_userstr(ctx, id, item.strip()))
items = (item.strip() for item in userstr.split(','))
items = (item for item in items if item)
data = [await cls._setting._parse_userstr(ctx, id, item, **kwargs) for item in items]
if cls._force_unique:
data = list(set(data))