mirror of
https://github.com/brandons209/Red-bot-Cogs.git
synced 2024-05-18 19:32:29 +12:00
add age verification for roles
This commit is contained in:
parent
db0e283177
commit
b56b54578a
|
@ -9,9 +9,19 @@ from typing import AsyncIterator, Tuple, Optional, Union, List, Dict, Literal
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
from discord.ext.commands import CogMeta as DPYCogMeta
|
from discord.ext.commands import CogMeta as DPYCogMeta
|
||||||
from redbot.core import checks, commands, bank
|
from redbot.core import checks, commands, bank, modlog
|
||||||
from redbot.core.config import Config
|
from redbot.core.config import Config
|
||||||
from redbot.core.utils.chat_formatting import box, pagify, warning, humanize_list
|
from redbot.core.utils.chat_formatting import (
|
||||||
|
box,
|
||||||
|
pagify,
|
||||||
|
warning,
|
||||||
|
humanize_list,
|
||||||
|
error,
|
||||||
|
info,
|
||||||
|
)
|
||||||
|
from redbot.core.utils.predicates import MessagePredicate
|
||||||
|
from dateutil import parser
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
from .events import EventMixin
|
from .events import EventMixin
|
||||||
from .exceptions import (
|
from .exceptions import (
|
||||||
|
@ -60,8 +70,8 @@ class RoleManagement(
|
||||||
Cog for role management
|
Cog for role management
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__author__ = "mikeshardmind(Sinbad), DiscordLiz"
|
__author__ = "mikeshardmind(Sinbad), DiscordLiz, Brandons209"
|
||||||
__version__ = "323.1.4"
|
__version__ = "325.0.0"
|
||||||
|
|
||||||
def format_help_for_context(self, ctx):
|
def format_help_for_context(self, ctx):
|
||||||
pre_processed = super().format_help_for_context(ctx)
|
pre_processed = super().format_help_for_context(ctx)
|
||||||
|
@ -69,8 +79,12 @@ class RoleManagement(
|
||||||
|
|
||||||
def __init__(self, bot):
|
def __init__(self, bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
self.config = Config.get_conf(self, identifier=78631113035100160, force_registration=True)
|
self.config = Config.get_conf(
|
||||||
self.config.register_global(handled_variation=False, handled_full_str_emoji=False)
|
self, identifier=78631113035100160, force_registration=True
|
||||||
|
)
|
||||||
|
self.config.register_global(
|
||||||
|
handled_variation=False, handled_full_str_emoji=False
|
||||||
|
)
|
||||||
self.config.register_role(
|
self.config.register_role(
|
||||||
exclusive_to={},
|
exclusive_to={},
|
||||||
requires_any=[],
|
requires_any=[],
|
||||||
|
@ -84,13 +98,16 @@ class RoleManagement(
|
||||||
subscription=0,
|
subscription=0,
|
||||||
subscribed_users={},
|
subscribed_users={},
|
||||||
dm_msg=None,
|
dm_msg=None,
|
||||||
|
age_verification=None,
|
||||||
) # subscribed_users maps str(user.id)-> end time in unix timestamp
|
) # subscribed_users maps str(user.id)-> end time in unix timestamp
|
||||||
self.config.register_member(roles=[], forbidden=[])
|
self.config.register_member(roles=[], forbidden=[], birthday=None)
|
||||||
self.config.init_custom("REACTROLE", 2)
|
self.config.init_custom("REACTROLE", 2)
|
||||||
self.config.register_custom(
|
self.config.register_custom(
|
||||||
"REACTROLE", roleid=None, channelid=None, guildid=None
|
"REACTROLE", roleid=None, channelid=None, guildid=None
|
||||||
) # ID : Message.id, str(React)
|
) # ID : Message.id, str(React)
|
||||||
self.config.register_guild(notify_channel=None, s_roles=[], free_roles=[], join_roles=[])
|
self.config.register_guild(
|
||||||
|
notify_channel=None, s_roles=[], free_roles=[], join_roles=[], age_log=False
|
||||||
|
)
|
||||||
self._ready = asyncio.Event()
|
self._ready = asyncio.Event()
|
||||||
self._start_task: Optional[asyncio.Task] = None
|
self._start_task: Optional[asyncio.Task] = None
|
||||||
self.loop = asyncio.get_event_loop()
|
self.loop = asyncio.get_event_loop()
|
||||||
|
@ -146,6 +163,19 @@ class RoleManagement(
|
||||||
await self.config.custom("REACTROLE").set(data)
|
await self.config.custom("REACTROLE").set(data)
|
||||||
await self.config.handled_full_str_emoji.set(True)
|
await self.config.handled_full_str_emoji.set(True)
|
||||||
|
|
||||||
|
# register casetype for age
|
||||||
|
age_case = {
|
||||||
|
"name": "Date of Birth Added",
|
||||||
|
"default_setting": True,
|
||||||
|
"image": "🧓",
|
||||||
|
"case_str": "Date of Birth Added",
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
await modlog.register_casetypes([age_case])
|
||||||
|
except RuntimeError:
|
||||||
|
pass
|
||||||
|
|
||||||
self._ready.set()
|
self._ready.set()
|
||||||
|
|
||||||
async def wait_for_ready(self):
|
async def wait_for_ready(self):
|
||||||
|
@ -225,7 +255,9 @@ class RoleManagement(
|
||||||
|
|
||||||
role_data = await self.sub_helper(guild, role, role_data)
|
role_data = await self.sub_helper(guild, role, role_data)
|
||||||
|
|
||||||
await self.config.role(role).subscribed_users.set(role_data["subscribed_users"])
|
await self.config.role(role).subscribed_users.set(
|
||||||
|
role_data["subscribed_users"]
|
||||||
|
)
|
||||||
if len(role_data["subscribed_users"]) == 0:
|
if len(role_data["subscribed_users"]) == 0:
|
||||||
s_roles.remove(role_id)
|
s_roles.remove(role_id)
|
||||||
|
|
||||||
|
@ -240,6 +272,32 @@ class RoleManagement(
|
||||||
|
|
||||||
return cost
|
return cost
|
||||||
|
|
||||||
|
@commands.guild_only()
|
||||||
|
@commands.bot_has_permissions(manage_roles=True)
|
||||||
|
@checks.admin_or_permissions(manage_roles=True)
|
||||||
|
@commands.command()
|
||||||
|
async def changeage(self, ctx: GuildContext, member: discord.Member, birthday: str):
|
||||||
|
"""
|
||||||
|
Manually update the birthday of a user.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
dob = parser.parse(birthday)
|
||||||
|
except:
|
||||||
|
await ctx.send(error("Invalid date format!"), delete_after=30)
|
||||||
|
return
|
||||||
|
|
||||||
|
if dob.year == datetime.now().year:
|
||||||
|
await ctx.send(
|
||||||
|
error(
|
||||||
|
f"Invalid date format, please make sure to include your birth year."
|
||||||
|
),
|
||||||
|
delete_after=30,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
await self.config.member(member).birthday.set(dob.strftime("%m/%d/%Y"))
|
||||||
|
await ctx.tick()
|
||||||
|
|
||||||
@commands.guild_only()
|
@commands.guild_only()
|
||||||
@commands.bot_has_permissions(manage_roles=True)
|
@commands.bot_has_permissions(manage_roles=True)
|
||||||
@checks.admin_or_permissions(manage_roles=True)
|
@checks.admin_or_permissions(manage_roles=True)
|
||||||
|
@ -250,7 +308,9 @@ class RoleManagement(
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not await self.all_are_valid_roles(ctx, role):
|
if not await self.all_are_valid_roles(ctx, role):
|
||||||
return await ctx.maybe_send_embed("Can't do that. Discord role heirarchy applies here.")
|
return await ctx.maybe_send_embed(
|
||||||
|
"Can't do that. Discord role heirarchy applies here."
|
||||||
|
)
|
||||||
|
|
||||||
if not await self.config.role(role).sticky():
|
if not await self.config.role(role).sticky():
|
||||||
return await ctx.send("This only works on sticky roles.")
|
return await ctx.send("This only works on sticky roles.")
|
||||||
|
@ -266,7 +326,9 @@ class RoleManagement(
|
||||||
await ctx.maybe_send_embed("They are in the guild...assigned anyway.")
|
await ctx.maybe_send_embed("They are in the guild...assigned anyway.")
|
||||||
else:
|
else:
|
||||||
|
|
||||||
async with self.config.member_from_ids(ctx.guild.id, user_id).roles() as sticky:
|
async with self.config.member_from_ids(
|
||||||
|
ctx.guild.id, user_id
|
||||||
|
).roles() as sticky:
|
||||||
if role.id not in sticky:
|
if role.id not in sticky:
|
||||||
sticky.append(role.id)
|
sticky.append(role.id)
|
||||||
|
|
||||||
|
@ -327,7 +389,9 @@ class RoleManagement(
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not await self.all_are_valid_roles(ctx, role):
|
if not await self.all_are_valid_roles(ctx, role):
|
||||||
return await ctx.maybe_send_embed("Can't do that. Discord role heirarchy applies here.")
|
return await ctx.maybe_send_embed(
|
||||||
|
"Can't do that. Discord role heirarchy applies here."
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
message = await channel.fetch_message(msgid)
|
message = await channel.fetch_message(msgid)
|
||||||
|
@ -352,7 +416,9 @@ class RoleManagement(
|
||||||
try:
|
try:
|
||||||
await message.add_reaction(_emoji)
|
await message.add_reaction(_emoji)
|
||||||
except discord.HTTPException:
|
except discord.HTTPException:
|
||||||
return await ctx.maybe_send_embed("Hmm, that message couldn't be reacted to")
|
return await ctx.maybe_send_embed(
|
||||||
|
"Hmm, that message couldn't be reacted to"
|
||||||
|
)
|
||||||
|
|
||||||
cfg = self.config.custom("REACTROLE", str(message.id), eid)
|
cfg = self.config.custom("REACTROLE", str(message.id), eid)
|
||||||
await cfg.set(
|
await cfg.set(
|
||||||
|
@ -372,15 +438,21 @@ class RoleManagement(
|
||||||
@commands.bot_has_permissions(manage_roles=True)
|
@commands.bot_has_permissions(manage_roles=True)
|
||||||
@checks.admin_or_permissions(manage_guild=True)
|
@checks.admin_or_permissions(manage_guild=True)
|
||||||
@commands.command(name="roleunbind")
|
@commands.command(name="roleunbind")
|
||||||
async def unbind_role_from_reactions(self, ctx: commands.Context, role: discord.Role, msgid: int, emoji: str):
|
async def unbind_role_from_reactions(
|
||||||
|
self, ctx: commands.Context, role: discord.Role, msgid: int, emoji: str
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
unbinds a role from a reaction on a message
|
unbinds a role from a reaction on a message
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not await self.all_are_valid_roles(ctx, role):
|
if not await self.all_are_valid_roles(ctx, role):
|
||||||
return await ctx.maybe_send_embed("Can't do that. Discord role heirarchy applies here.")
|
return await ctx.maybe_send_embed(
|
||||||
|
"Can't do that. Discord role heirarchy applies here."
|
||||||
|
)
|
||||||
|
|
||||||
await self.config.custom("REACTROLE", f"{msgid}", self.strip_variations(emoji)).clear()
|
await self.config.custom(
|
||||||
|
"REACTROLE", f"{msgid}", self.strip_variations(emoji)
|
||||||
|
).clear()
|
||||||
await ctx.tick()
|
await ctx.tick()
|
||||||
|
|
||||||
@commands.guild_only()
|
@commands.guild_only()
|
||||||
|
@ -393,8 +465,37 @@ class RoleManagement(
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@rgroup.command(name="age")
|
||||||
|
async def rg_age_verification(self, ctx, role: discord.Role, age: int):
|
||||||
|
"""
|
||||||
|
Add an age verification requirement for a role
|
||||||
|
|
||||||
|
Users will have to give the bot their birthdate in order to obtain a role.
|
||||||
|
|
||||||
|
An age of 0 will disable age verification.
|
||||||
|
"""
|
||||||
|
if age == 0:
|
||||||
|
await self.config.role(role).age_verification.set(None)
|
||||||
|
elif age < 0:
|
||||||
|
await ctx.send(error("Age must be greater than or equal to 0."))
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
await self.config.role(role).age_verification.set(age)
|
||||||
|
|
||||||
|
await ctx.tick()
|
||||||
|
|
||||||
|
@rgroup.command(name="agelog")
|
||||||
|
async def rg_age_verification_log(self, ctx, log: bool):
|
||||||
|
"""
|
||||||
|
Log age verification to modlog
|
||||||
|
"""
|
||||||
|
await self.config.guild(ctx.guild).age_log.set(log)
|
||||||
|
await ctx.tick()
|
||||||
|
|
||||||
@rgroup.command(name="addwith")
|
@rgroup.command(name="addwith")
|
||||||
async def rg_addwith(self, ctx: GuildContext, add_role: discord.Role, *roles: discord.Role):
|
async def rg_addwith(
|
||||||
|
self, ctx: GuildContext, add_role: discord.Role, *roles: discord.Role
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Sets a list of roles to add to a user when they receive
|
Sets a list of roles to add to a user when they receive
|
||||||
the role specifed by `add_role`
|
the role specifed by `add_role`
|
||||||
|
@ -426,7 +527,12 @@ class RoleManagement(
|
||||||
|
|
||||||
use_embeds = await ctx.embed_requested()
|
use_embeds = await ctx.embed_requested()
|
||||||
react_roles = "\n".join(
|
react_roles = "\n".join(
|
||||||
[msg async for msg in self.build_messages_for_react_roles(*ctx.guild.roles, use_embeds=use_embeds)]
|
[
|
||||||
|
msg
|
||||||
|
async for msg in self.build_messages_for_react_roles(
|
||||||
|
*ctx.guild.roles, use_embeds=use_embeds
|
||||||
|
)
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
if not react_roles:
|
if not react_roles:
|
||||||
|
@ -437,7 +543,9 @@ class RoleManagement(
|
||||||
|
|
||||||
color = await ctx.embed_colour() if use_embeds else None
|
color = await ctx.embed_colour() if use_embeds else None
|
||||||
|
|
||||||
for page in pagify(react_roles, escape_mass_mentions=False, page_length=1800, shorten_by=0):
|
for page in pagify(
|
||||||
|
react_roles, escape_mass_mentions=False, page_length=1800, shorten_by=0
|
||||||
|
):
|
||||||
# unrolling iterative calling of ctx.maybe_send_embed
|
# unrolling iterative calling of ctx.maybe_send_embed
|
||||||
if use_embeds:
|
if use_embeds:
|
||||||
await ctx.send(embed=discord.Embed(description=page, color=color))
|
await ctx.send(embed=discord.Embed(description=page, color=color))
|
||||||
|
@ -445,7 +553,9 @@ class RoleManagement(
|
||||||
await ctx.send(page)
|
await ctx.send(page)
|
||||||
|
|
||||||
@rgroup.command(name="dm-message")
|
@rgroup.command(name="dm-message")
|
||||||
async def rg_dm_message(self, ctx: GuildContext, role: discord.Role, *, msg: str = None):
|
async def rg_dm_message(
|
||||||
|
self, ctx: GuildContext, role: discord.Role, *, msg: str = None
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Set message to DM to user when they obtain the role.
|
Set message to DM to user when they obtain the role.
|
||||||
Will send it in the channel they ran the command if DM fails to send.
|
Will send it in the channel they ran the command if DM fails to send.
|
||||||
|
@ -511,7 +621,9 @@ class RoleManagement(
|
||||||
return
|
return
|
||||||
roles = [ctx.guild.get_role(role) for role in roles]
|
roles = [ctx.guild.get_role(role) for role in roles]
|
||||||
missing = len([role for role in roles if role is None])
|
missing = len([role for role in roles if role is None])
|
||||||
roles = [f"{i+1}.{role.name}" for i, role in enumerate(roles) if role is not None]
|
roles = [
|
||||||
|
f"{i+1}.{role.name}" for i, role in enumerate(roles) if role is not None
|
||||||
|
]
|
||||||
|
|
||||||
msg = "\n".join(sorted(roles))
|
msg = "\n".join(sorted(roles))
|
||||||
msg = pagify(msg)
|
msg = pagify(msg)
|
||||||
|
@ -532,13 +644,19 @@ class RoleManagement(
|
||||||
f"\n{'is' if rsets['sticky'] else 'is not'} sticky."
|
f"\n{'is' if rsets['sticky'] else 'is not'} sticky."
|
||||||
)
|
)
|
||||||
if rsets["requires_any"]:
|
if rsets["requires_any"]:
|
||||||
rstring = ", ".join(r.name for r in ctx.guild.roles if r.id in rsets["requires_any"])
|
rstring = ", ".join(
|
||||||
|
r.name for r in ctx.guild.roles if r.id in rsets["requires_any"]
|
||||||
|
)
|
||||||
output += f"\nThis role requires any of the following roles: {rstring}"
|
output += f"\nThis role requires any of the following roles: {rstring}"
|
||||||
if rsets["requires_all"]:
|
if rsets["requires_all"]:
|
||||||
rstring = ", ".join(r.name for r in ctx.guild.roles if r.id in rsets["requires_all"])
|
rstring = ", ".join(
|
||||||
|
r.name for r in ctx.guild.roles if r.id in rsets["requires_all"]
|
||||||
|
)
|
||||||
output += f"\nThis role requires all of the following roles: {rstring}"
|
output += f"\nThis role requires all of the following roles: {rstring}"
|
||||||
if rsets["add_with"]:
|
if rsets["add_with"]:
|
||||||
rstring = ", ".join(r.name for r in ctx.guild.roles if r.id in rsets["add_with"])
|
rstring = ", ".join(
|
||||||
|
r.name for r in ctx.guild.roles if r.id in rsets["add_with"]
|
||||||
|
)
|
||||||
output += f"\nThis role when added will also be added with the following roles: {rstring}"
|
output += f"\nThis role when added will also be added with the following roles: {rstring}"
|
||||||
if rsets["exclusive_to"]:
|
if rsets["exclusive_to"]:
|
||||||
rstring = ""
|
rstring = ""
|
||||||
|
@ -562,11 +680,17 @@ class RoleManagement(
|
||||||
dm_msg = rsets["dm_msg"]
|
dm_msg = rsets["dm_msg"]
|
||||||
output += f"\nDM Message: {box(dm_msg)}"
|
output += f"\nDM Message: {box(dm_msg)}"
|
||||||
|
|
||||||
|
if rsets["age_verification"]:
|
||||||
|
age = rsets["age_verification"]
|
||||||
|
output += f"\nMinimum Age: `{age}`"
|
||||||
|
|
||||||
for page in pagify(output):
|
for page in pagify(output):
|
||||||
await ctx.send(page)
|
await ctx.send(page)
|
||||||
|
|
||||||
@rgroup.command(name="cost")
|
@rgroup.command(name="cost")
|
||||||
async def make_purchasable(self, ctx: GuildContext, cost: int, *, role: discord.Role):
|
async def make_purchasable(
|
||||||
|
self, ctx: GuildContext, cost: int, *, role: discord.Role
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Makes a role purchasable for a specified cost.
|
Makes a role purchasable for a specified cost.
|
||||||
Cost must be a number greater than 0.
|
Cost must be a number greater than 0.
|
||||||
|
@ -579,7 +703,9 @@ class RoleManagement(
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not await self.all_are_valid_roles(ctx, role):
|
if not await self.all_are_valid_roles(ctx, role):
|
||||||
return await ctx.maybe_send_embed("Can't do that. Discord role heirarchy applies here.")
|
return await ctx.maybe_send_embed(
|
||||||
|
"Can't do that. Discord role heirarchy applies here."
|
||||||
|
)
|
||||||
|
|
||||||
if cost < 0:
|
if cost < 0:
|
||||||
return await ctx.send_help()
|
return await ctx.send_help()
|
||||||
|
@ -607,7 +733,9 @@ class RoleManagement(
|
||||||
(etc)
|
(etc)
|
||||||
"""
|
"""
|
||||||
if not await self.all_are_valid_roles(ctx, role):
|
if not await self.all_are_valid_roles(ctx, role):
|
||||||
return await ctx.maybe_send_embed("Can't do that. Discord role heirarchy applies here.")
|
return await ctx.maybe_send_embed(
|
||||||
|
"Can't do that. Discord role heirarchy applies here."
|
||||||
|
)
|
||||||
role_cost = await self.config.role(role).cost()
|
role_cost = await self.config.role(role).cost()
|
||||||
|
|
||||||
if role_cost == 0:
|
if role_cost == 0:
|
||||||
|
@ -630,7 +758,9 @@ class RoleManagement(
|
||||||
await ctx.send(f"Subscription set to {parse_seconds(time.total_seconds())}.")
|
await ctx.send(f"Subscription set to {parse_seconds(time.total_seconds())}.")
|
||||||
|
|
||||||
@rgroup.command(name="forbid")
|
@rgroup.command(name="forbid")
|
||||||
async def forbid_role(self, ctx: GuildContext, role: discord.Role, *, user: discord.Member):
|
async def forbid_role(
|
||||||
|
self, ctx: GuildContext, role: discord.Role, *, user: discord.Member
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Forbids a user from gaining a specific role.
|
Forbids a user from gaining a specific role.
|
||||||
"""
|
"""
|
||||||
|
@ -642,7 +772,9 @@ class RoleManagement(
|
||||||
await ctx.tick()
|
await ctx.tick()
|
||||||
|
|
||||||
@rgroup.command(name="unforbid")
|
@rgroup.command(name="unforbid")
|
||||||
async def unforbid_role(self, ctx: GuildContext, role: discord.Role, *, user: discord.Member):
|
async def unforbid_role(
|
||||||
|
self, ctx: GuildContext, role: discord.Role, *, user: discord.Member
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Unforbids a user from gaining a specific role.
|
Unforbids a user from gaining a specific role.
|
||||||
"""
|
"""
|
||||||
|
@ -654,7 +786,9 @@ class RoleManagement(
|
||||||
await ctx.tick()
|
await ctx.tick()
|
||||||
|
|
||||||
@rgroup.command(name="exclusive")
|
@rgroup.command(name="exclusive")
|
||||||
async def set_exclusivity(self, ctx: GuildContext, group: str, *roles: discord.Role):
|
async def set_exclusivity(
|
||||||
|
self, ctx: GuildContext, group: str, *roles: discord.Role
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Set exclusive roles for group
|
Set exclusive roles for group
|
||||||
Takes 2 or more roles and sets them as exclusive to eachother
|
Takes 2 or more roles and sets them as exclusive to eachother
|
||||||
|
@ -672,12 +806,16 @@ class RoleManagement(
|
||||||
async with self.config.role(role).exclusive_to() as ex_list:
|
async with self.config.role(role).exclusive_to() as ex_list:
|
||||||
if group not in ex_list.keys():
|
if group not in ex_list.keys():
|
||||||
ex_list[group] = []
|
ex_list[group] = []
|
||||||
ex_list[group].extend([r.id for r in _roles if r != role and r.id not in ex_list[group]])
|
ex_list[group].extend(
|
||||||
|
[r.id for r in _roles if r != role and r.id not in ex_list[group]]
|
||||||
|
)
|
||||||
|
|
||||||
await ctx.tick()
|
await ctx.tick()
|
||||||
|
|
||||||
@rgroup.command(name="unexclusive")
|
@rgroup.command(name="unexclusive")
|
||||||
async def unset_exclusivity(self, ctx: GuildContext, group: str, *roles: discord.Role):
|
async def unset_exclusivity(
|
||||||
|
self, ctx: GuildContext, group: str, *roles: discord.Role
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Remove exclusive roles for group
|
Remove exclusive roles for group
|
||||||
Takes any number of roles, and removes their exclusivity settings
|
Takes any number of roles, and removes their exclusivity settings
|
||||||
|
@ -695,21 +833,29 @@ class RoleManagement(
|
||||||
ex_list = await self.config.role(role).exclusive_to()
|
ex_list = await self.config.role(role).exclusive_to()
|
||||||
if group not in ex_list.keys():
|
if group not in ex_list.keys():
|
||||||
continue
|
continue
|
||||||
ex_list[group] = [idx for idx in ex_list if idx not in [r.id for r in _roles]]
|
ex_list[group] = [
|
||||||
|
idx for idx in ex_list if idx not in [r.id for r in _roles]
|
||||||
|
]
|
||||||
if not ex_list[group]:
|
if not ex_list[group]:
|
||||||
del ex_list[group]
|
del ex_list[group]
|
||||||
await self.config.role(role).exclusive_to.set(ex_list)
|
await self.config.role(role).exclusive_to.set(ex_list)
|
||||||
await ctx.tick()
|
await ctx.tick()
|
||||||
|
|
||||||
@rgroup.command(name="sticky")
|
@rgroup.command(name="sticky")
|
||||||
async def setsticky(self, ctx: GuildContext, role: discord.Role, sticky: bool = None):
|
async def setsticky(
|
||||||
|
self, ctx: GuildContext, role: discord.Role, sticky: bool = None
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
sets a role as sticky if used without a settings, gets the current ones
|
sets a role as sticky if used without a settings, gets the current ones
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if sticky is None:
|
if sticky is None:
|
||||||
is_sticky = await self.config.role(role).sticky()
|
is_sticky = await self.config.role(role).sticky()
|
||||||
return await ctx.send("{role} {verb} sticky".format(role=role.name, verb=("is" if is_sticky else "is not")))
|
return await ctx.send(
|
||||||
|
"{role} {verb} sticky".format(
|
||||||
|
role=role.name, verb=("is" if is_sticky else "is not")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
await self.config.role(role).sticky.set(sticky)
|
await self.config.role(role).sticky.set(sticky)
|
||||||
if sticky:
|
if sticky:
|
||||||
|
@ -745,7 +891,9 @@ class RoleManagement(
|
||||||
await ctx.tick()
|
await ctx.tick()
|
||||||
|
|
||||||
@rgroup.command(name="selfrem")
|
@rgroup.command(name="selfrem")
|
||||||
async def selfrem(self, ctx: GuildContext, role: discord.Role, removable: bool = None):
|
async def selfrem(
|
||||||
|
self, ctx: GuildContext, role: discord.Role, removable: bool = None
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Sets if a role is self-removable (default False)
|
Sets if a role is self-removable (default False)
|
||||||
|
|
||||||
|
@ -755,14 +903,18 @@ class RoleManagement(
|
||||||
if removable is None:
|
if removable is None:
|
||||||
is_removable = await self.config.role(role).self_removable()
|
is_removable = await self.config.role(role).self_removable()
|
||||||
return await ctx.send(
|
return await ctx.send(
|
||||||
"{role} {verb} self-removable".format(role=role.name, verb=("is" if is_removable else "is not"))
|
"{role} {verb} self-removable".format(
|
||||||
|
role=role.name, verb=("is" if is_removable else "is not")
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
await self.config.role(role).self_removable.set(removable)
|
await self.config.role(role).self_removable.set(removable)
|
||||||
await ctx.tick()
|
await ctx.tick()
|
||||||
|
|
||||||
@rgroup.command(name="selfadd")
|
@rgroup.command(name="selfadd")
|
||||||
async def selfadd(self, ctx: GuildContext, role: discord.Role, assignable: bool = None):
|
async def selfadd(
|
||||||
|
self, ctx: GuildContext, role: discord.Role, assignable: bool = None
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Sets if a role is self-assignable via command
|
Sets if a role is self-assignable via command
|
||||||
|
|
||||||
|
@ -774,7 +926,9 @@ class RoleManagement(
|
||||||
if assignable is None:
|
if assignable is None:
|
||||||
is_assignable = await self.config.role(role).self_role()
|
is_assignable = await self.config.role(role).self_role()
|
||||||
return await ctx.send(
|
return await ctx.send(
|
||||||
"{role} {verb} self-assignable".format(role=role.name, verb=("is" if is_assignable else "is not"))
|
"{role} {verb} self-assignable".format(
|
||||||
|
role=role.name, verb=("is" if is_assignable else "is not")
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
await self.config.role(role).self_role.set(assignable)
|
await self.config.role(role).self_role.set(assignable)
|
||||||
|
@ -823,7 +977,9 @@ class RoleManagement(
|
||||||
return
|
return
|
||||||
roles = [ctx.guild.get_role(role) for role in roles]
|
roles = [ctx.guild.get_role(role) for role in roles]
|
||||||
missing = len([role for role in roles if role is None])
|
missing = len([role for role in roles if role is None])
|
||||||
roles = [f"{i+1}.{role.name}" for i, role in enumerate(roles) if role is not None]
|
roles = [
|
||||||
|
f"{i+1}.{role.name}" for i, role in enumerate(roles) if role is not None
|
||||||
|
]
|
||||||
|
|
||||||
msg = "\n".join(sorted(roles))
|
msg = "\n".join(sorted(roles))
|
||||||
msg = pagify(msg)
|
msg = pagify(msg)
|
||||||
|
@ -868,7 +1024,9 @@ class RoleManagement(
|
||||||
embed = discord.Embed(title="Roles", colour=ctx.guild.me.colour)
|
embed = discord.Embed(title="Roles", colour=ctx.guild.me.colour)
|
||||||
embed.set_footer(text="You can only have one role in the same unique group!")
|
embed.set_footer(text="You can only have one role in the same unique group!")
|
||||||
i = 0
|
i = 0
|
||||||
for role, (cost, sub, ex_groups) in sorted(data.items(), key=lambda kv: kv[1][0]):
|
for role, (cost, sub, ex_groups) in sorted(
|
||||||
|
data.items(), key=lambda kv: kv[1][0]
|
||||||
|
):
|
||||||
if ex_groups:
|
if ex_groups:
|
||||||
groups = humanize_list(list(ex_groups.keys()))
|
groups = humanize_list(list(ex_groups.keys()))
|
||||||
else:
|
else:
|
||||||
|
@ -904,7 +1062,9 @@ class RoleManagement(
|
||||||
cost = await self.config.role(role).cost()
|
cost = await self.config.role(role).cost()
|
||||||
subscription = await self.config.role(role).subscription()
|
subscription = await self.config.role(role).subscription()
|
||||||
except PermissionOrHierarchyException:
|
except PermissionOrHierarchyException:
|
||||||
await ctx.send("I cannot assign roles which I can not manage. (Discord Hierarchy)")
|
await ctx.send(
|
||||||
|
"I cannot assign roles which I can not manage. (Discord Hierarchy)"
|
||||||
|
)
|
||||||
except MissingRequirementsException as e:
|
except MissingRequirementsException as e:
|
||||||
msg = ""
|
msg = ""
|
||||||
if e.miss_all:
|
if e.miss_all:
|
||||||
|
@ -922,16 +1082,27 @@ class RoleManagement(
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
if not eligible:
|
if not eligible:
|
||||||
return await ctx.send(f"You aren't allowed to add `{role}` to yourself {ctx.author.mention}!")
|
return await ctx.send(
|
||||||
|
f"You aren't allowed to add `{role}` to yourself {ctx.author.mention}!"
|
||||||
|
)
|
||||||
|
|
||||||
if not cost:
|
if not cost:
|
||||||
return await ctx.send("This role doesn't have a cost. Please try again using `[p]selfrole add`.")
|
return await ctx.send(
|
||||||
|
"This role doesn't have a cost. Please try again using `[p]selfrole add`."
|
||||||
|
)
|
||||||
|
|
||||||
|
if not await self.verify_age(role, ctx=ctx):
|
||||||
|
return await ctx.send(
|
||||||
|
"You do not meet the minimum age requiremnt for this role, if you think this is an error please contact a staff member."
|
||||||
|
)
|
||||||
|
|
||||||
free_roles = await self.config.guild(ctx.guild).free_roles()
|
free_roles = await self.config.guild(ctx.guild).free_roles()
|
||||||
currency_name = await bank.get_currency_name(ctx.guild)
|
currency_name = await bank.get_currency_name(ctx.guild)
|
||||||
for m_role in ctx.author.roles:
|
for m_role in ctx.author.roles:
|
||||||
if m_role.id in free_roles:
|
if m_role.id in free_roles:
|
||||||
await ctx.send(f"You're special, no {currency_name} will be deducted from your account.")
|
await ctx.send(
|
||||||
|
f"You're special, no {currency_name} will be deducted from your account."
|
||||||
|
)
|
||||||
cost = 0
|
cost = 0
|
||||||
# await self.update_roles_atomically(who=ctx.author, give=[role], remove=remove)
|
# await self.update_roles_atomically(who=ctx.author, give=[role], remove=remove)
|
||||||
# await ctx.tick()
|
# await ctx.tick()
|
||||||
|
@ -941,11 +1112,15 @@ class RoleManagement(
|
||||||
if cost > 0:
|
if cost > 0:
|
||||||
await bank.withdraw_credits(ctx.author, cost)
|
await bank.withdraw_credits(ctx.author, cost)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return await ctx.send(f"You don't have enough {currency_name} (Cost: {cost} {currency_name})")
|
return await ctx.send(
|
||||||
|
f"You don't have enough {currency_name} (Cost: {cost} {currency_name})"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
if subscription > 0:
|
if subscription > 0:
|
||||||
if cost > 0:
|
if cost > 0:
|
||||||
await ctx.send(f"{role.name} will be renewed every {parse_seconds(subscription)}")
|
await ctx.send(
|
||||||
|
f"{role.name} will be renewed every {parse_seconds(subscription)}"
|
||||||
|
)
|
||||||
async with self.config.role(role).subscribed_users() as s:
|
async with self.config.role(role).subscribed_users() as s:
|
||||||
s[str(ctx.author.id)] = time.time() + subscription
|
s[str(ctx.author.id)] = time.time() + subscription
|
||||||
async with self.config.guild(ctx.guild).s_roles() as s:
|
async with self.config.guild(ctx.guild).s_roles() as s:
|
||||||
|
@ -957,7 +1132,9 @@ class RoleManagement(
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
f"Removed `{humanize_list([r.name for r in remove])}` role{plural} since they are exclusive to the role you added."
|
f"Removed `{humanize_list([r.name for r in remove])}` role{plural} since they are exclusive to the role you added."
|
||||||
)
|
)
|
||||||
await self.update_roles_atomically(who=ctx.author, give=[role], remove=remove)
|
await self.update_roles_atomically(
|
||||||
|
who=ctx.author, give=[role], remove=remove
|
||||||
|
)
|
||||||
await self.dm_user(ctx, role)
|
await self.dm_user(ctx, role)
|
||||||
await ctx.tick()
|
await ctx.tick()
|
||||||
|
|
||||||
|
@ -974,7 +1151,9 @@ class RoleManagement(
|
||||||
eligible = await self.config.role(role).self_role()
|
eligible = await self.config.role(role).self_role()
|
||||||
cost = await self.config.role(role).cost()
|
cost = await self.config.role(role).cost()
|
||||||
except PermissionOrHierarchyException:
|
except PermissionOrHierarchyException:
|
||||||
await ctx.send("I cannot assign roles which I can not manage. (Discord Hierarchy)")
|
await ctx.send(
|
||||||
|
"I cannot assign roles which I can not manage. (Discord Hierarchy)"
|
||||||
|
)
|
||||||
except MissingRequirementsException as e:
|
except MissingRequirementsException as e:
|
||||||
msg = ""
|
msg = ""
|
||||||
if e.miss_all:
|
if e.miss_all:
|
||||||
|
@ -992,11 +1171,19 @@ class RoleManagement(
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
if not eligible:
|
if not eligible:
|
||||||
await ctx.send(f"You aren't allowed to add `{role}` to yourself {ctx.author.mention}!")
|
await ctx.send(
|
||||||
|
f"You aren't allowed to add `{role}` to yourself {ctx.author.mention}!"
|
||||||
|
)
|
||||||
|
|
||||||
|
elif not await self.verify_age(role, ctx=ctx):
|
||||||
|
return await ctx.send(
|
||||||
|
"You do not meet the minimum age requiremnt for this role, if you think this is an error please contact a staff member."
|
||||||
|
)
|
||||||
|
|
||||||
elif cost:
|
elif cost:
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
"This role is not free. " "Please use `[p]selfrole buy` if you would like to purchase it."
|
"This role is not free. "
|
||||||
|
"Please use `[p]selfrole buy` if you would like to purchase it."
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
if remove:
|
if remove:
|
||||||
|
@ -1004,7 +1191,9 @@ class RoleManagement(
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
f"Removed `{humanize_list([r.name for r in remove])}` role{plural} since they are exclusive to the role you added."
|
f"Removed `{humanize_list([r.name for r in remove])}` role{plural} since they are exclusive to the role you added."
|
||||||
)
|
)
|
||||||
await self.update_roles_atomically(who=ctx.author, give=[role], remove=remove)
|
await self.update_roles_atomically(
|
||||||
|
who=ctx.author, give=[role], remove=remove
|
||||||
|
)
|
||||||
await self.dm_user(ctx, role)
|
await self.dm_user(ctx, role)
|
||||||
await ctx.tick()
|
await ctx.tick()
|
||||||
|
|
||||||
|
@ -1025,11 +1214,15 @@ class RoleManagement(
|
||||||
pass
|
pass
|
||||||
await ctx.tick()
|
await ctx.tick()
|
||||||
else:
|
else:
|
||||||
await ctx.send(f"You aren't allowed to remove `{role}` from yourself {ctx.author.mention}!`")
|
await ctx.send(
|
||||||
|
f"You aren't allowed to remove `{role}` from yourself {ctx.author.mention}!`"
|
||||||
|
)
|
||||||
|
|
||||||
# Stuff for clean interaction with react role entries
|
# Stuff for clean interaction with react role entries
|
||||||
|
|
||||||
async def build_messages_for_react_roles(self, *roles: discord.Role, use_embeds=True) -> AsyncIterator[str]:
|
async def build_messages_for_react_roles(
|
||||||
|
self, *roles: discord.Role, use_embeds=True
|
||||||
|
) -> AsyncIterator[str]:
|
||||||
"""
|
"""
|
||||||
Builds info.
|
Builds info.
|
||||||
|
|
||||||
|
@ -1055,13 +1248,15 @@ class RoleManagement(
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
link = (
|
link = (
|
||||||
f"unknown message with id {message_id}" f" (use `roleset fixup` to find missing data for this)"
|
f"unknown message with id {message_id}"
|
||||||
|
f" (use `roleset fixup` to find missing data for this)"
|
||||||
)
|
)
|
||||||
|
|
||||||
emoji: Union[discord.Emoji, str]
|
emoji: Union[discord.Emoji, str]
|
||||||
if emoji_info.isdigit():
|
if emoji_info.isdigit():
|
||||||
emoji = (
|
emoji = (
|
||||||
discord.utils.get(self.bot.emojis, id=int(emoji_info)) or f"A custom enoji with id {emoji_info}"
|
discord.utils.get(self.bot.emojis, id=int(emoji_info))
|
||||||
|
or f"A custom enoji with id {emoji_info}"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
emoji = emoji_info
|
emoji = emoji_info
|
||||||
|
@ -1069,6 +1264,118 @@ class RoleManagement(
|
||||||
react_m = f"{role.name} is bound to {emoji} on {link}"
|
react_m = f"{role.name} is bound to {emoji} on {link}"
|
||||||
yield react_m
|
yield react_m
|
||||||
|
|
||||||
|
async def verify_age(
|
||||||
|
self,
|
||||||
|
role: discord.Role,
|
||||||
|
ctx: GuildContext = None,
|
||||||
|
member: discord.Member = None,
|
||||||
|
) -> bool:
|
||||||
|
"""
|
||||||
|
Verify age of a user.
|
||||||
|
|
||||||
|
Returns True if age is successfully verified, false otherwise.
|
||||||
|
"""
|
||||||
|
if ctx is not None:
|
||||||
|
member = ctx.author
|
||||||
|
|
||||||
|
guild = member.guild
|
||||||
|
dob = await self.config.member(member).birthday()
|
||||||
|
min_age = await self.config.role(role).age_verification()
|
||||||
|
age_log = await self.config.guild(guild).age_log()
|
||||||
|
today = datetime.utcnow().date()
|
||||||
|
|
||||||
|
if min_age is None:
|
||||||
|
return True
|
||||||
|
|
||||||
|
if dob is not None:
|
||||||
|
dob = parser.parse(dob).date()
|
||||||
|
age = today.year - dob.year
|
||||||
|
|
||||||
|
# check to see if their birthday has passed
|
||||||
|
dob = dob.replace(year=today.year)
|
||||||
|
if dob > today:
|
||||||
|
# birthday hasn't passed, subtract one from age
|
||||||
|
age -= 1
|
||||||
|
|
||||||
|
return age > min_age
|
||||||
|
|
||||||
|
if ctx is not None:
|
||||||
|
await ctx.send(
|
||||||
|
info(
|
||||||
|
"Please check your DMs with me in order to continue getting this role!"
|
||||||
|
),
|
||||||
|
delete_after=30,
|
||||||
|
)
|
||||||
|
|
||||||
|
# get dob of user
|
||||||
|
try:
|
||||||
|
age_msg = f"Hello! In order to get the `{role}` role in `{guild}`, you must provide your **full date of birth** in order to verify your age. Please send it here."
|
||||||
|
await member.send(age_msg)
|
||||||
|
pred = MessagePredicate.same_context(user=member)
|
||||||
|
msg = await self.bot.wait_for("message", check=pred, timeout=60)
|
||||||
|
except discord.Forbidden: # TODO: send message in guild telling user to allow dms?
|
||||||
|
return False
|
||||||
|
except discord.HTTPException:
|
||||||
|
return False
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
await member.send(
|
||||||
|
error(
|
||||||
|
f"Took too long, the {role} role has not been added to you in {guild}!\nPlease try again."
|
||||||
|
),
|
||||||
|
delete_after=30,
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
dob = parser.parse(msg.content.strip())
|
||||||
|
except:
|
||||||
|
await member.send(
|
||||||
|
error(
|
||||||
|
f"Invalid date format, the {role} role has not been added to you in {guild}!\nPlease try again."
|
||||||
|
),
|
||||||
|
delete_after=30,
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
dob = dob.date()
|
||||||
|
if dob.year == today.year:
|
||||||
|
await member.send(
|
||||||
|
error(
|
||||||
|
f"Invalid date format, please make sure to include your birth year, the {role} role has not been added to you in {guild}!\nPlease try again."
|
||||||
|
),
|
||||||
|
delete_after=30,
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
dob_str = dob.strftime("%m/%d/%Y")
|
||||||
|
await member.send(
|
||||||
|
f"Thank you! Please check back in `{guild}` to confirm you obtained the role. If not, you may not meet the age requirement for the role."
|
||||||
|
)
|
||||||
|
await self.config.member(member).birthday.set(dob_str)
|
||||||
|
if age_log:
|
||||||
|
try:
|
||||||
|
await modlog.create_case(
|
||||||
|
self.bot,
|
||||||
|
guild,
|
||||||
|
datetime.now(),
|
||||||
|
"Date of Birth Added",
|
||||||
|
member,
|
||||||
|
moderator=member,
|
||||||
|
reason=f"Date of birth added for `{member}`: `{dob_str}`\n\nRole: `{role}`",
|
||||||
|
)
|
||||||
|
except: # TODO: warn staff
|
||||||
|
pass
|
||||||
|
|
||||||
|
age = today.year - dob.year
|
||||||
|
|
||||||
|
# check to see if their birthday has passed
|
||||||
|
dob = dob.replace(year=today.year)
|
||||||
|
if dob > today:
|
||||||
|
# birthday hasn't passed, subtract one from age
|
||||||
|
age -= 1
|
||||||
|
|
||||||
|
return age > min_age
|
||||||
|
|
||||||
async def dm_user(self, ctx: GuildContext, role: discord.Role):
|
async def dm_user(self, ctx: GuildContext, role: discord.Role):
|
||||||
"""
|
"""
|
||||||
DM user if dm_msg set for role.
|
DM user if dm_msg set for role.
|
||||||
|
@ -1085,7 +1392,9 @@ class RoleManagement(
|
||||||
)
|
)
|
||||||
await ctx.send(dm_msg)
|
await ctx.send(dm_msg)
|
||||||
|
|
||||||
async def get_react_role_entries(self, role: discord.Role) -> AsyncIterator[Tuple[str, str, dict]]:
|
async def get_react_role_entries(
|
||||||
|
self, role: discord.Role
|
||||||
|
) -> AsyncIterator[Tuple[str, str, dict]]:
|
||||||
"""
|
"""
|
||||||
yields:
|
yields:
|
||||||
str, str, dict
|
str, str, dict
|
||||||
|
|
|
@ -68,7 +68,9 @@ class EventMixin(MixinMeta):
|
||||||
for r in gained:
|
for r in gained:
|
||||||
add_with = await self.config.role_from_id(r).add_with()
|
add_with = await self.config.role_from_id(r).add_with()
|
||||||
if add_with:
|
if add_with:
|
||||||
to_add = [discord.utils.get(after.guild.roles, id=add) for add in add_with]
|
to_add = [
|
||||||
|
discord.utils.get(after.guild.roles, id=add) for add in add_with
|
||||||
|
]
|
||||||
await after.add_roles(*to_add, reason=f"add with role {r}")
|
await after.add_roles(*to_add, reason=f"add with role {r}")
|
||||||
|
|
||||||
for r in sym_diff:
|
for r in sym_diff:
|
||||||
|
@ -117,7 +119,9 @@ class EventMixin(MixinMeta):
|
||||||
await member.add_roles(*to_add)
|
await member.add_roles(*to_add)
|
||||||
|
|
||||||
@commands.Cog.listener()
|
@commands.Cog.listener()
|
||||||
async def on_raw_reaction_add(self, payload: discord.raw_models.RawReactionActionEvent):
|
async def on_raw_reaction_add(
|
||||||
|
self, payload: discord.raw_models.RawReactionActionEvent
|
||||||
|
):
|
||||||
await self.wait_for_ready()
|
await self.wait_for_ready()
|
||||||
if not payload.guild_id:
|
if not payload.guild_id:
|
||||||
return
|
return
|
||||||
|
@ -153,6 +157,15 @@ class EventMixin(MixinMeta):
|
||||||
if role is None or role in member.roles:
|
if role is None or role in member.roles:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if not await self.verify_age(role, member=member):
|
||||||
|
try:
|
||||||
|
await member.send(
|
||||||
|
f"You do not meet the minimum age requiremnt for `{role}`, if you think this is an error please contact a staff member."
|
||||||
|
)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
remove = await self.is_self_assign_eligible(member, role)
|
remove = await self.is_self_assign_eligible(member, role)
|
||||||
except (RoleManagementException, PermissionOrHierarchyException):
|
except (RoleManagementException, PermissionOrHierarchyException):
|
||||||
|
@ -167,7 +180,9 @@ class EventMixin(MixinMeta):
|
||||||
await self.update_roles_atomically(who=member, give=[role], remove=remove)
|
await self.update_roles_atomically(who=member, give=[role], remove=remove)
|
||||||
|
|
||||||
@commands.Cog.listener()
|
@commands.Cog.listener()
|
||||||
async def on_raw_reaction_remove(self, payload: discord.raw_models.RawReactionActionEvent):
|
async def on_raw_reaction_remove(
|
||||||
|
self, payload: discord.raw_models.RawReactionActionEvent
|
||||||
|
):
|
||||||
await self.wait_for_ready()
|
await self.wait_for_ready()
|
||||||
if not payload.guild_id:
|
if not payload.guild_id:
|
||||||
return
|
return
|
||||||
|
|
Loading…
Reference in a new issue