feature (reaction-roles): Configuration command.

New monolithic `rroles` configuration command.
Complete logging and setting implementation in RR tracker.
Improve strings in RR settings.

Add special `NEWPAGE` manual section parsed by the help command.
Add `tabulated` method for `ObjectSettings` for easy display.
Add `_parse_create` switch for the `Role` setting type.
This commit is contained in:
2021-10-18 15:28:14 +03:00
parent 006f2cfd6d
commit cfa3c90841
7 changed files with 912 additions and 265 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -37,6 +37,10 @@ class required_role(setting_types.Role, RoleMessageSetting):
else:
return "All members can now use these reaction roles."
@classmethod
def _get_guildid(cls, id: int, **kwargs):
return reaction_role_messages.fetch(id).guildid
@RoleMessageSettings.attach_setting
class removable(setting_types.Boolean, RoleMessageSetting):
@@ -88,7 +92,7 @@ class maximum(setting_types.Integer, RoleMessageSetting):
@property
def success_response(self):
if self.value:
return "Members can get a maximum of `{}` roles from this message."
return "Members can get a maximum of `{}` roles from this message.".format(self.value)
else:
return "Members can now get all the roles from this mesage."
@@ -205,7 +209,7 @@ class price(setting_types.Integer, ReactionSetting):
@classmethod
def _format_data(cls, id, data, **kwargs):
if data is None:
if not data:
return "Free"
else:
return "`{}` coins".format(data)
@@ -213,9 +217,9 @@ class price(setting_types.Integer, ReactionSetting):
@property
def success_response(self):
if self.value is not None:
return "This role now costs `{}` coins.".format(self.value)
return "{{reaction.emoji}} {{reaction.role.mention}} now costs `{}` coins.".format(self.value)
else:
return "This role is free."
return "{reaction.emoji} {reaction.role.mention} is now free."
@ReactionSettings.attach_setting
@@ -243,6 +247,8 @@ class timeout(setting_types.Duration, ReactionSetting):
@property
def success_response(self):
if self.value is not None:
return "Roles will timeout `{}` after selection.".format(self.formatted)
return "{{reaction.emoji}} {{reaction.role.mention}} will timeout `{}` after selection.".format(
self.formatted
)
else:
return "Roles will never timeout after selection."
return "{reaction.emoji} {reaction.role.mention} will never timeout after selection."

View File

@@ -18,17 +18,17 @@ from .data import reaction_role_messages, reaction_role_reactions # , reaction_
from .settings import RoleMessageSettings, ReactionSettings
class ReactionRoleReaction(PartialEmoji):
class ReactionRoleReaction:
"""
Light data class representing a reaction role reaction.
Extends PartialEmoji for comparison with discord Emojis.
"""
__slots__ = ('reactionid', '_message', '_role')
__slots__ = ('reactionid', '_emoji', '_message', '_role')
def __init__(self, reactionid, message=None, **kwargs):
self.reactionid = reactionid
self._message: ReactionRoleMessage = None
self._role = None
self._emoji = None
@classmethod
def create(cls, messageid, roleid, emoji: PartialEmoji, message=None, **kwargs) -> 'ReactionRoleReaction':
@@ -47,6 +47,17 @@ class ReactionRoleReaction(PartialEmoji):
)
return cls(row.reactionid, message=message)
@property
def emoji(self) -> PartialEmoji:
if self._emoji is None:
data = self.data
self._emoji = PartialEmoji(
name=data.emoji_name,
animated=data.emoji_animated,
id=data.emoji_id,
)
return self._emoji
@property
def data(self) -> Row:
return reaction_role_reactions.fetch(self.reactionid)
@@ -69,31 +80,6 @@ class ReactionRoleReaction(PartialEmoji):
self._role = guild.get_role(self.data.roleid)
return self._role
# PartialEmoji properties
@property
def animated(self) -> bool:
return self.data.emoji_animated
@property
def name(self) -> str:
return self.data.emoji_name
@name.setter
def name(self, value):
"""
Name setter.
The emoji name may get updated while the emoji itself remains the same.
"""
self.data.emoji_name = value
@property
def id(self) -> Optional[int]:
return self.data.emoji_id
@property
def _state(self):
return client._connection
class ReactionRoleMessage:
"""
@@ -147,6 +133,20 @@ class ReactionRoleMessage:
# Return the constructed ReactionRoleMessage
return rmsg
def delete(self):
"""
Delete this ReactionRoleMessage.
"""
# Remove message from cache
self._messages.pop(self.messageid, None)
# Remove reactions from cache
reactionids = [reaction.reactionid for reaction in self.reactions]
[self._reactions.pop(reactionid, None) for reactionid in reactionids]
# Remove message from data
reaction_role_messages.delete_where(messageid=self.messageid)
@property
def data(self) -> Row:
"""
@@ -242,7 +242,7 @@ class ReactionRoleMessage:
"""
event_log = GuildSettings(self.guild.id).event_log
async with self._locks[payload.user_id]:
reaction = next((reaction for reaction in self.reactions if reaction == payload.emoji), None)
reaction = next((reaction for reaction in self.reactions if reaction.emoji == payload.emoji), None)
if reaction:
# User pressed a live reaction. Process!
member = payload.member
@@ -428,7 +428,7 @@ class ReactionRoleMessage:
if self.settings.removable.value:
event_log = GuildSettings(self.guild.id).event_log
async with self._locks[payload.user_id]:
reaction = next((reaction for reaction in self.reactions if reaction == payload.emoji), None)
reaction = next((reaction for reaction in self.reactions if reaction.emoji == payload.emoji), None)
if reaction:
# User removed a live reaction. Process!
member = self.guild.get_member(payload.user_id)