mirror of
https://github.com/brandons209/Red-bot-Cogs.git
synced 2024-05-19 11:52:55 +12:00
forgot formmating
This commit is contained in:
parent
217fe41183
commit
54c72d8369
|
@ -28,9 +28,7 @@ class MixinMeta(ABC):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
async def is_self_assign_eligible(
|
async def is_self_assign_eligible(self, who: discord.Member, role: discord.Role) -> List[discord.Role]:
|
||||||
self, who: discord.Member, role: discord.Role
|
|
||||||
) -> List[discord.Role]:
|
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
|
|
|
@ -19,9 +19,7 @@ class RoleSyntaxConverter(NamedTuple):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def convert(cls, ctx: Context, argument: str):
|
async def convert(cls, ctx: Context, argument: str):
|
||||||
parser = NoExitParser(
|
parser = NoExitParser(description="Role management syntax help", add_help=False, allow_abbrev=True)
|
||||||
description="Role management syntax help", add_help=False, allow_abbrev=True
|
|
||||||
)
|
|
||||||
parser.add_argument("--add", nargs="*", dest="add", default=[])
|
parser.add_argument("--add", nargs="*", dest="add", default=[])
|
||||||
parser.add_argument("--remove", nargs="*", dest="remove", default=[])
|
parser.add_argument("--remove", nargs="*", dest="remove", default=[])
|
||||||
try:
|
try:
|
||||||
|
@ -68,9 +66,7 @@ class ComplexActionConverter(NamedTuple):
|
||||||
parser.add_argument("--has-any", nargs="*", dest="any", default=[])
|
parser.add_argument("--has-any", nargs="*", dest="any", default=[])
|
||||||
parser.add_argument("--has-all", nargs="*", dest="all", default=[])
|
parser.add_argument("--has-all", nargs="*", dest="all", default=[])
|
||||||
parser.add_argument("--has-none", nargs="*", dest="none", default=[])
|
parser.add_argument("--has-none", nargs="*", dest="none", default=[])
|
||||||
parser.add_argument(
|
parser.add_argument("--has-no-roles", action="store_true", default=False, dest="noroles")
|
||||||
"--has-no-roles", action="store_true", default=False, dest="noroles"
|
|
||||||
)
|
|
||||||
parser.add_argument("--has-perms", nargs="*", dest="hasperm", default=[])
|
parser.add_argument("--has-perms", nargs="*", dest="hasperm", default=[])
|
||||||
parser.add_argument("--any-perm", nargs="*", dest="anyperm", default=[])
|
parser.add_argument("--any-perm", nargs="*", dest="anyperm", default=[])
|
||||||
parser.add_argument("--not-perm", nargs="*", dest="notperm", default=[])
|
parser.add_argument("--not-perm", nargs="*", dest="notperm", default=[])
|
||||||
|
@ -82,15 +78,9 @@ class ComplexActionConverter(NamedTuple):
|
||||||
parser.add_argument("--above", dest="above", type=str, default=None)
|
parser.add_argument("--above", dest="above", type=str, default=None)
|
||||||
parser.add_argument("--below", dest="below", type=str, default=None)
|
parser.add_argument("--below", dest="below", type=str, default=None)
|
||||||
hum_or_bot = parser.add_mutually_exclusive_group()
|
hum_or_bot = parser.add_mutually_exclusive_group()
|
||||||
hum_or_bot.add_argument(
|
hum_or_bot.add_argument("--only-humans", action="store_true", default=False, dest="humans")
|
||||||
"--only-humans", action="store_true", default=False, dest="humans"
|
hum_or_bot.add_argument("--only-bots", action="store_true", default=False, dest="bots")
|
||||||
)
|
hum_or_bot.add_argument("--everyone", action="store_true", default=False, dest="everyone")
|
||||||
hum_or_bot.add_argument(
|
|
||||||
"--only-bots", action="store_true", default=False, dest="bots"
|
|
||||||
)
|
|
||||||
hum_or_bot.add_argument(
|
|
||||||
"--everyone", action="store_true", default=False, dest="everyone"
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
vals = vars(parser.parse_args(shlex.split(argument)))
|
vals = vars(parser.parse_args(shlex.split(argument)))
|
||||||
|
@ -131,10 +121,7 @@ class ComplexActionConverter(NamedTuple):
|
||||||
|
|
||||||
for attr in ("hasperm", "anyperm", "notperm"):
|
for attr in ("hasperm", "anyperm", "notperm"):
|
||||||
|
|
||||||
vals[attr] = [
|
vals[attr] = [i.replace("_", " ").lower().replace(" ", "_").replace("server", "guild") for i in vals[attr]]
|
||||||
i.replace("_", " ").lower().replace(" ", "_").replace("server", "guild")
|
|
||||||
for i in vals[attr]
|
|
||||||
]
|
|
||||||
if any(perm not in dir(discord.Permissions) for perm in vals[attr]):
|
if any(perm not in dir(discord.Permissions) for perm in vals[attr]):
|
||||||
raise BadArgument("You gave an invalid permission")
|
raise BadArgument("You gave an invalid permission")
|
||||||
|
|
||||||
|
@ -169,30 +156,20 @@ class ComplexSearchConverter(NamedTuple):
|
||||||
parser.add_argument("--has-any", nargs="*", dest="any", default=[])
|
parser.add_argument("--has-any", nargs="*", dest="any", default=[])
|
||||||
parser.add_argument("--has-all", nargs="*", dest="all", default=[])
|
parser.add_argument("--has-all", nargs="*", dest="all", default=[])
|
||||||
parser.add_argument("--has-none", nargs="*", dest="none", default=[])
|
parser.add_argument("--has-none", nargs="*", dest="none", default=[])
|
||||||
parser.add_argument(
|
parser.add_argument("--has-no-roles", action="store_true", default=False, dest="noroles")
|
||||||
"--has-no-roles", action="store_true", default=False, dest="noroles"
|
|
||||||
)
|
|
||||||
parser.add_argument("--has-perms", nargs="*", dest="hasperm", default=[])
|
parser.add_argument("--has-perms", nargs="*", dest="hasperm", default=[])
|
||||||
parser.add_argument("--any-perm", nargs="*", dest="anyperm", default=[])
|
parser.add_argument("--any-perm", nargs="*", dest="anyperm", default=[])
|
||||||
parser.add_argument("--not-perm", nargs="*", dest="notperm", default=[])
|
parser.add_argument("--not-perm", nargs="*", dest="notperm", default=[])
|
||||||
parser.add_argument("--csv", action="store_true", default=False)
|
parser.add_argument("--csv", action="store_true", default=False)
|
||||||
parser.add_argument(
|
parser.add_argument("--has-exactly-nroles", dest="quantity", type=int, default=None)
|
||||||
"--has-exactly-nroles", dest="quantity", type=int, default=None
|
|
||||||
)
|
|
||||||
parser.add_argument("--has-more-than-nroles", dest="gt", type=int, default=None)
|
parser.add_argument("--has-more-than-nroles", dest="gt", type=int, default=None)
|
||||||
parser.add_argument("--has-less-than-nroles", dest="lt", type=int, default=None)
|
parser.add_argument("--has-less-than-nroles", dest="lt", type=int, default=None)
|
||||||
parser.add_argument("--above", dest="above", type=str, default=None)
|
parser.add_argument("--above", dest="above", type=str, default=None)
|
||||||
parser.add_argument("--below", dest="below", type=str, default=None)
|
parser.add_argument("--below", dest="below", type=str, default=None)
|
||||||
hum_or_bot = parser.add_mutually_exclusive_group()
|
hum_or_bot = parser.add_mutually_exclusive_group()
|
||||||
hum_or_bot.add_argument(
|
hum_or_bot.add_argument("--only-humans", action="store_true", default=False, dest="humans")
|
||||||
"--only-humans", action="store_true", default=False, dest="humans"
|
hum_or_bot.add_argument("--only-bots", action="store_true", default=False, dest="bots")
|
||||||
)
|
hum_or_bot.add_argument("--everyone", action="store_true", default=False, dest="everyone")
|
||||||
hum_or_bot.add_argument(
|
|
||||||
"--only-bots", action="store_true", default=False, dest="bots"
|
|
||||||
)
|
|
||||||
hum_or_bot.add_argument(
|
|
||||||
"--everyone", action="store_true", default=False, dest="everyone"
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
vals = vars(parser.parse_args(shlex.split(argument)))
|
vals = vars(parser.parse_args(shlex.split(argument)))
|
||||||
except Exception:
|
except Exception:
|
||||||
|
@ -229,10 +206,7 @@ class ComplexSearchConverter(NamedTuple):
|
||||||
|
|
||||||
for attr in ("hasperm", "anyperm", "notperm"):
|
for attr in ("hasperm", "anyperm", "notperm"):
|
||||||
|
|
||||||
vals[attr] = [
|
vals[attr] = [i.replace("_", " ").lower().replace(" ", "_").replace("server", "guild") for i in vals[attr]]
|
||||||
i.replace("_", " ").lower().replace(" ", "_").replace("server", "guild")
|
|
||||||
for i in vals[attr]
|
|
||||||
]
|
|
||||||
if any(perm not in dir(discord.Permissions) for perm in vals[attr]):
|
if any(perm not in dir(discord.Permissions) for perm in vals[attr]):
|
||||||
raise BadArgument("You gave an invalid permission")
|
raise BadArgument("You gave an invalid permission")
|
||||||
|
|
||||||
|
|
|
@ -38,15 +38,13 @@ class CompositeMetaClass(DPYCogMeta, ABCMeta):
|
||||||
pass # MRO is fine on __new__ with super() use
|
pass # MRO is fine on __new__ with super() use
|
||||||
# no need to manually ensure both get handled here.
|
# no need to manually ensure both get handled here.
|
||||||
|
|
||||||
|
|
||||||
MIN_SUB_TIME = 3600
|
MIN_SUB_TIME = 3600
|
||||||
SLEEP_TIME = 300
|
SLEEP_TIME = 300
|
||||||
|
|
||||||
|
|
||||||
class RoleManagement(
|
class RoleManagement(
|
||||||
UtilMixin,
|
UtilMixin, MassManagementMixin, EventMixin, commands.Cog, metaclass=CompositeMetaClass,
|
||||||
MassManagementMixin,
|
|
||||||
EventMixin,
|
|
||||||
commands.Cog,
|
|
||||||
metaclass=CompositeMetaClass,
|
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Cog for role management
|
Cog for role management
|
||||||
|
@ -61,12 +59,8 @@ class RoleManagement(
|
||||||
|
|
||||||
def __init__(self, bot):
|
def __init__(self, bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
self.config = Config.get_conf(
|
self.config = Config.get_conf(self, identifier=78631113035100160, force_registration=True)
|
||||||
self, identifier=78631113035100160, force_registration=True
|
self.config.register_global(handled_variation=False, handled_full_str_emoji=False)
|
||||||
)
|
|
||||||
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=[],
|
||||||
|
@ -77,8 +71,8 @@ class RoleManagement(
|
||||||
protected=False,
|
protected=False,
|
||||||
cost=0,
|
cost=0,
|
||||||
subscription=0,
|
subscription=0,
|
||||||
subscribed_users={}
|
subscribed_users={},
|
||||||
)#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=[])
|
||||||
self.config.init_custom("REACTROLE", 2)
|
self.config.init_custom("REACTROLE", 2)
|
||||||
self.config.register_custom(
|
self.config.register_custom(
|
||||||
|
@ -155,7 +149,7 @@ class RoleManagement(
|
||||||
now_time = time.time()
|
now_time = time.time()
|
||||||
if end_time <= now_time:
|
if end_time <= now_time:
|
||||||
member = guild.get_member(int(user_id))
|
member = guild.get_member(int(user_id))
|
||||||
if not member: # clean absent members
|
if not member: # clean absent members
|
||||||
del role_data["subscribed_users"][user_id]
|
del role_data["subscribed_users"][user_id]
|
||||||
continue
|
continue
|
||||||
# charge user
|
# charge user
|
||||||
|
@ -172,7 +166,7 @@ class RoleManagement(
|
||||||
await bank.withdraw_credits(member, cost)
|
await bank.withdraw_credits(member, cost)
|
||||||
msg += f"\n\nNo further action is required! You'll be charged again in {parse_seconds(curr_sub)}."
|
msg += f"\n\nNo further action is required! You'll be charged again in {parse_seconds(curr_sub)}."
|
||||||
role_data["subscribed_users"][user_id] = now_time + curr_sub
|
role_data["subscribed_users"][user_id] = now_time + curr_sub
|
||||||
except ValueError: # user is poor
|
except ValueError: # user is poor
|
||||||
msg += f"\n\nHowever, you do not have enough {currency_name} to cover the subscription. The role will be removed."
|
msg += f"\n\nHowever, you do not have enough {currency_name} to cover the subscription. The role will be removed."
|
||||||
await self.update_roles_atomically(who=member, remove=[role])
|
await self.update_roles_atomically(who=member, remove=[role])
|
||||||
del role_data["subscribed_users"][user_id]
|
del role_data["subscribed_users"][user_id]
|
||||||
|
@ -202,7 +196,7 @@ class RoleManagement(
|
||||||
async with self.config.guild(guild).s_roles() as s_roles:
|
async with self.config.guild(guild).s_roles() as s_roles:
|
||||||
for role_id in reversed(s_roles):
|
for role_id in reversed(s_roles):
|
||||||
role = guild.get_role(role_id)
|
role = guild.get_role(role_id)
|
||||||
if not role: # clean stale subs if role is deleted
|
if not role: # clean stale subs if role is deleted
|
||||||
s_roles.remove(role_id)
|
s_roles.remove(role_id)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -210,9 +204,7 @@ 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(
|
await self.config.role(role).subscribed_users.set(role_data["subscribed_users"])
|
||||||
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)
|
||||||
|
|
||||||
|
@ -226,9 +218,7 @@ 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(
|
return await ctx.maybe_send_embed("Can't do that. Discord role heirarchy applies here.")
|
||||||
"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.")
|
||||||
|
@ -244,9 +234,7 @@ 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(
|
async with self.config.member_from_ids(ctx.guild.id, user_id).roles() as sticky:
|
||||||
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)
|
||||||
|
|
||||||
|
@ -292,12 +280,7 @@ class RoleManagement(
|
||||||
@checks.admin_or_permissions(manage_guild=True)
|
@checks.admin_or_permissions(manage_guild=True)
|
||||||
@commands.command(name="rolebind")
|
@commands.command(name="rolebind")
|
||||||
async def bind_role_to_reactions(
|
async def bind_role_to_reactions(
|
||||||
self,
|
self, ctx: GuildContext, role: discord.Role, channel: discord.TextChannel, msgid: int, emoji: str,
|
||||||
ctx: GuildContext,
|
|
||||||
role: discord.Role,
|
|
||||||
channel: discord.TextChannel,
|
|
||||||
msgid: int,
|
|
||||||
emoji: str,
|
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Binds a role to a reaction on a message...
|
Binds a role to a reaction on a message...
|
||||||
|
@ -307,9 +290,7 @@ 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(
|
return await ctx.maybe_send_embed("Can't do that. Discord role heirarchy applies here.")
|
||||||
"Can't do that. Discord role heirarchy applies here."
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
message = await channel.fetch_message(msgid)
|
message = await channel.fetch_message(msgid)
|
||||||
|
@ -334,17 +315,11 @@ 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(
|
return await ctx.maybe_send_embed("Hmm, that message couldn't be reacted to")
|
||||||
"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(
|
||||||
{
|
{"roleid": role.id, "channelid": message.channel.id, "guildid": role.guild.id,}
|
||||||
"roleid": role.id,
|
|
||||||
"channelid": message.channel.id,
|
|
||||||
"guildid": role.guild.id,
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
f"Remember, the reactions only function according to "
|
f"Remember, the reactions only function according to "
|
||||||
|
@ -356,21 +331,15 @@ 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(
|
async def unbind_role_from_reactions(self, ctx: commands.Context, role: discord.Role, msgid: int, emoji: str):
|
||||||
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(
|
return await ctx.maybe_send_embed("Can't do that. Discord role heirarchy applies here.")
|
||||||
"Can't do that. Discord role heirarchy applies here."
|
|
||||||
)
|
|
||||||
|
|
||||||
await self.config.custom(
|
await self.config.custom("REACTROLE", f"{msgid}", self.strip_variations(emoji)).clear()
|
||||||
"REACTROLE", f"{msgid}", self.strip_variations(emoji)
|
|
||||||
).clear()
|
|
||||||
await ctx.tick()
|
await ctx.tick()
|
||||||
|
|
||||||
@commands.guild_only()
|
@commands.guild_only()
|
||||||
|
@ -392,12 +361,7 @@ 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:
|
||||||
|
@ -408,9 +372,7 @@ 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(
|
for page in pagify(react_roles, escape_mass_mentions=False, page_length=1800, shorten_by=0):
|
||||||
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))
|
||||||
|
@ -431,22 +393,14 @@ 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(
|
rstring = ", ".join(r.name for r in ctx.guild.roles if r.id in rsets["requires_any"])
|
||||||
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(
|
rstring = ", ".join(r.name for r in ctx.guild.roles if r.id in rsets["requires_all"])
|
||||||
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["exclusive_to"]:
|
if rsets["exclusive_to"]:
|
||||||
rstring = ", ".join(
|
rstring = ", ".join(r.name for r in ctx.guild.roles if r.id in rsets["exclusive_to"])
|
||||||
r.name for r in ctx.guild.roles if r.id in rsets["exclusive_to"]
|
output += f"\nThis role is mutually exclusive to the following roles: {rstring}"
|
||||||
)
|
|
||||||
output += (
|
|
||||||
f"\nThis role is mutually exclusive to the following roles: {rstring}"
|
|
||||||
)
|
|
||||||
if rsets["cost"]:
|
if rsets["cost"]:
|
||||||
curr = await bank.get_currency_name(ctx.guild)
|
curr = await bank.get_currency_name(ctx.guild)
|
||||||
cost = rsets["cost"]
|
cost = rsets["cost"]
|
||||||
|
@ -462,9 +416,7 @@ class RoleManagement(
|
||||||
await ctx.send(page)
|
await ctx.send(page)
|
||||||
|
|
||||||
@rgroup.command(name="cost")
|
@rgroup.command(name="cost")
|
||||||
async def make_purchasable(
|
async def make_purchasable(self, ctx: GuildContext, cost: int, *, role: discord.Role):
|
||||||
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.
|
||||||
|
@ -477,9 +429,7 @@ 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(
|
return await ctx.maybe_send_embed("Can't do that. Discord role heirarchy applies here.")
|
||||||
"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()
|
||||||
|
@ -507,9 +457,7 @@ 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(
|
return await ctx.maybe_send_embed("Can't do that. Discord role heirarchy applies here.")
|
||||||
"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:
|
||||||
|
@ -532,9 +480,7 @@ 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(
|
async def forbid_role(self, ctx: GuildContext, role: discord.Role, *, user: discord.Member):
|
||||||
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.
|
||||||
"""
|
"""
|
||||||
|
@ -546,9 +492,7 @@ class RoleManagement(
|
||||||
await ctx.tick()
|
await ctx.tick()
|
||||||
|
|
||||||
@rgroup.command(name="unforbid")
|
@rgroup.command(name="unforbid")
|
||||||
async def unforbid_role(
|
async def unforbid_role(self, ctx: GuildContext, role: discord.Role, *, user: discord.Member):
|
||||||
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.
|
||||||
"""
|
"""
|
||||||
|
@ -572,9 +516,7 @@ class RoleManagement(
|
||||||
|
|
||||||
for role in _roles:
|
for role in _roles:
|
||||||
async with self.config.role(role).exclusive_to() as ex_list:
|
async with self.config.role(role).exclusive_to() as ex_list:
|
||||||
ex_list.extend(
|
ex_list.extend([r.id for r in _roles if r != role and r.id not in ex_list])
|
||||||
[r.id for r in _roles if r != role and r.id not in ex_list]
|
|
||||||
)
|
|
||||||
await ctx.tick()
|
await ctx.tick()
|
||||||
|
|
||||||
@rgroup.command(name="unexclusive")
|
@rgroup.command(name="unexclusive")
|
||||||
|
@ -595,20 +537,14 @@ class RoleManagement(
|
||||||
await ctx.tick()
|
await ctx.tick()
|
||||||
|
|
||||||
@rgroup.command(name="sticky")
|
@rgroup.command(name="sticky")
|
||||||
async def setsticky(
|
async def setsticky(self, ctx: GuildContext, role: discord.Role, sticky: bool = None):
|
||||||
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(
|
return await ctx.send("{role} {verb} sticky".format(role=role.name, verb=("is" if is_sticky else "is not")))
|
||||||
"{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:
|
||||||
|
@ -619,7 +555,7 @@ class RoleManagement(
|
||||||
|
|
||||||
await ctx.tick()
|
await ctx.tick()
|
||||||
|
|
||||||
#TODO set roles who don't need to pay for roles
|
# TODO set roles who don't need to pay for roles
|
||||||
@rgroup.command(name="requireall")
|
@rgroup.command(name="requireall")
|
||||||
async def reqall(self, ctx: GuildContext, role: discord.Role, *roles: discord.Role):
|
async def reqall(self, ctx: GuildContext, role: discord.Role, *roles: discord.Role):
|
||||||
"""
|
"""
|
||||||
|
@ -645,9 +581,7 @@ class RoleManagement(
|
||||||
await ctx.tick()
|
await ctx.tick()
|
||||||
|
|
||||||
@rgroup.command(name="selfrem")
|
@rgroup.command(name="selfrem")
|
||||||
async def selfrem(
|
async def selfrem(self, ctx: GuildContext, role: discord.Role, removable: bool = None):
|
||||||
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)
|
||||||
|
|
||||||
|
@ -657,18 +591,14 @@ 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} {verb} self-removable".format(role=role.name, verb=("is" if is_removable else "is not"))
|
||||||
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(
|
async def selfadd(self, ctx: GuildContext, role: discord.Role, assignable: bool = None):
|
||||||
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
|
||||||
|
|
||||||
|
@ -680,9 +610,7 @@ 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} {verb} self-assignable".format(role=role.name, verb=("is" if is_assignable else "is not"))
|
||||||
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)
|
||||||
|
@ -778,7 +706,8 @@ class RoleManagement(
|
||||||
for role, (cost, sub) in sorted(data.items(), key=lambda kv: kv[1]):
|
for role, (cost, sub) in sorted(data.items(), key=lambda kv: kv[1]):
|
||||||
embed.add_field(
|
embed.add_field(
|
||||||
name=f"__**{i+1}. {role.name}**__",
|
name=f"__**{i+1}. {role.name}**__",
|
||||||
value="%s%s" % ((f"Cost: {cost}" if cost else "Free"), (f", every {parse_seconds(sub)}" if sub else ""))
|
value="%s%s"
|
||||||
|
% ((f"Cost: {cost}" if cost else "Free"), (f", every {parse_seconds(sub)}" if sub else "")),
|
||||||
)
|
)
|
||||||
i += 1
|
i += 1
|
||||||
if i % 25 == 0:
|
if i % 25 == 0:
|
||||||
|
@ -802,37 +731,27 @@ class RoleManagement(
|
||||||
except RoleManagementException:
|
except RoleManagementException:
|
||||||
return
|
return
|
||||||
except PermissionOrHierarchyException:
|
except PermissionOrHierarchyException:
|
||||||
await ctx.send(
|
await ctx.send("I cannot assign roles which I can not manage. (Discord Hierarchy)")
|
||||||
"I cannot assign roles which I can not manage. (Discord Hierarchy)"
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
if not eligible:
|
if not eligible:
|
||||||
return await ctx.send(
|
return await ctx.send(f"You aren't allowed to add `{role}` to yourself {ctx.author.mention}!")
|
||||||
f"You aren't allowed to add `{role}` to yourself {ctx.author.mention}!"
|
|
||||||
)
|
|
||||||
|
|
||||||
if not cost:
|
if not cost:
|
||||||
return await ctx.send(
|
return await ctx.send("This role doesn't have a cost. Please try again using `[p]srole add`.")
|
||||||
"This role doesn't have a cost. Please try again using `[p]srole add`."
|
|
||||||
)
|
|
||||||
|
|
||||||
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.")
|
||||||
await self.update_roles_atomically(
|
await self.update_roles_atomically(who=ctx.author, give=[role], remove=remove)
|
||||||
who=ctx.author, give=[role], remove=remove
|
|
||||||
)
|
|
||||||
await ctx.tick()
|
await ctx.tick()
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await bank.withdraw_credits(ctx.author, cost)
|
await bank.withdraw_credits(ctx.author, cost)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return await ctx.send(
|
return await ctx.send(f"You don't have enough {currency_name} (Cost: {cost} {currency_name})")
|
||||||
f"You don't have enough {currency_name} (Cost: {cost} {currency_name})"
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
if subscription > 0:
|
if subscription > 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)}")
|
||||||
|
@ -842,9 +761,7 @@ class RoleManagement(
|
||||||
if role.id not in s:
|
if role.id not in s:
|
||||||
s.append(role.id)
|
s.append(role.id)
|
||||||
|
|
||||||
await self.update_roles_atomically(
|
await self.update_roles_atomically(who=ctx.author, give=[role], remove=remove)
|
||||||
who=ctx.author, give=[role], remove=remove
|
|
||||||
)
|
|
||||||
await ctx.tick()
|
await ctx.tick()
|
||||||
|
|
||||||
@srole.command(name="add")
|
@srole.command(name="add")
|
||||||
|
@ -862,24 +779,15 @@ class RoleManagement(
|
||||||
except RoleManagementException:
|
except RoleManagementException:
|
||||||
return
|
return
|
||||||
except PermissionOrHierarchyException:
|
except PermissionOrHierarchyException:
|
||||||
await ctx.send(
|
await ctx.send("I cannot assign roles which I can not manage. (Discord Hierarchy)")
|
||||||
"I cannot assign roles which I can not manage. (Discord Hierarchy)"
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
if not eligible:
|
if not eligible:
|
||||||
await ctx.send(
|
await ctx.send(f"You aren't allowed to add `{role}` to yourself {ctx.author.mention}!")
|
||||||
f"You aren't allowed to add `{role}` to yourself {ctx.author.mention}!"
|
|
||||||
)
|
|
||||||
|
|
||||||
elif cost:
|
elif cost:
|
||||||
await ctx.send(
|
await ctx.send("This role is not free. " "Please use `[p]srole buy` if you would like to purchase it.")
|
||||||
"This role is not free. "
|
|
||||||
"Please use `[p]srole buy` if you would like to purchase it."
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
await self.update_roles_atomically(
|
await self.update_roles_atomically(who=ctx.author, give=[role], remove=remove)
|
||||||
who=ctx.author, give=[role], remove=remove
|
|
||||||
)
|
|
||||||
await ctx.tick()
|
await ctx.tick()
|
||||||
|
|
||||||
@srole.command(name="remove")
|
@srole.command(name="remove")
|
||||||
|
@ -892,22 +800,18 @@ class RoleManagement(
|
||||||
return
|
return
|
||||||
if await self.config.role(role).self_removable():
|
if await self.config.role(role).self_removable():
|
||||||
await self.update_roles_atomically(who=ctx.author, remove=[role])
|
await self.update_roles_atomically(who=ctx.author, remove=[role])
|
||||||
try: # remove subscription, if any
|
try: # remove subscription, if any
|
||||||
async with self.config.role(role).subscribed_users() as s:
|
async with self.config.role(role).subscribed_users() as s:
|
||||||
del s[str(ctx.author.id)]
|
del s[str(ctx.author.id)]
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
await ctx.tick()
|
await ctx.tick()
|
||||||
else:
|
else:
|
||||||
await ctx.send(
|
await ctx.send(f"You aren't allowed to remove `{role}` from yourself {ctx.author.mention}!`")
|
||||||
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(
|
async def build_messages_for_react_roles(self, *roles: discord.Role, use_embeds=True) -> AsyncIterator[str]:
|
||||||
self, *roles: discord.Role, use_embeds=True
|
|
||||||
) -> AsyncIterator[str]:
|
|
||||||
"""
|
"""
|
||||||
Builds info.
|
Builds info.
|
||||||
|
|
||||||
|
@ -926,22 +830,16 @@ class RoleManagement(
|
||||||
|
|
||||||
channel_id = data.get("channelid", None)
|
channel_id = data.get("channelid", None)
|
||||||
if channel_id:
|
if channel_id:
|
||||||
link = linkfmt.format(
|
link = linkfmt.format(guild_id=role.guild.id, channel_id=channel_id, message_id=message_id,)
|
||||||
guild_id=role.guild.id,
|
|
||||||
channel_id=channel_id,
|
|
||||||
message_id=message_id,
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
link = (
|
link = (
|
||||||
f"unknown message with id {message_id}"
|
f"unknown message with id {message_id}" f" (use `roleset fixup` to find missing data for this)"
|
||||||
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))
|
discord.utils.get(self.bot.emojis, id=int(emoji_info)) or f"A custom enoji with id {emoji_info}"
|
||||||
or f"A custom enoji with id {emoji_info}"
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
emoji = emoji_info
|
emoji = emoji_info
|
||||||
|
@ -949,9 +847,7 @@ 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 get_react_role_entries(
|
async def get_react_role_entries(self, role: discord.Role) -> AsyncIterator[Tuple[str, str, dict]]:
|
||||||
self, role: discord.Role
|
|
||||||
) -> AsyncIterator[Tuple[str, str, dict]]:
|
|
||||||
"""
|
"""
|
||||||
yields:
|
yields:
|
||||||
str, str, dict
|
str, str, dict
|
||||||
|
|
|
@ -84,9 +84,7 @@ 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(
|
async def on_raw_reaction_add(self, payload: discord.raw_models.RawReactionActionEvent):
|
||||||
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
|
||||||
|
@ -127,9 +125,7 @@ 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(
|
async def on_raw_reaction_remove(self, payload: discord.raw_models.RawReactionActionEvent):
|
||||||
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
|
||||||
|
|
|
@ -4,9 +4,11 @@ from __future__ import annotations
|
||||||
class RoleManagementException(Exception):
|
class RoleManagementException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class PermissionOrHierarchyException(Exception):
|
class PermissionOrHierarchyException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class MissingRequirementsException(RoleManagementException):
|
class MissingRequirementsException(RoleManagementException):
|
||||||
def __init__(self, *, miss_any=None, miss_all=None):
|
def __init__(self, *, miss_any=None, miss_all=None):
|
||||||
self.miss_all = miss_all or []
|
self.miss_all = miss_all or []
|
||||||
|
|
|
@ -88,14 +88,12 @@ class MassManagementMixin(MixinMeta):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if query["anyperm"] and not any(
|
if query["anyperm"] and not any(
|
||||||
bool(value and perm in query["anyperm"])
|
bool(value and perm in query["anyperm"]) for perm, value in iter(m.guild_permissions)
|
||||||
for perm, value in iter(m.guild_permissions)
|
|
||||||
):
|
):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if query["notperm"] and any(
|
if query["notperm"] and any(
|
||||||
bool(value and perm in query["notperm"])
|
bool(value and perm in query["notperm"]) for perm, value in iter(m.guild_permissions)
|
||||||
for perm, value in iter(m.guild_permissions)
|
|
||||||
):
|
):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -126,11 +124,7 @@ class MassManagementMixin(MixinMeta):
|
||||||
|
|
||||||
@mrole.command(name="user")
|
@mrole.command(name="user")
|
||||||
async def mrole_user(
|
async def mrole_user(
|
||||||
self,
|
self, ctx: GuildContext, users: commands.Greedy[discord.Member], *, _query: RoleSyntaxConverter,
|
||||||
ctx: GuildContext,
|
|
||||||
users: commands.Greedy[discord.Member],
|
|
||||||
*,
|
|
||||||
_query: RoleSyntaxConverter,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
adds/removes roles to one or more users
|
adds/removes roles to one or more users
|
||||||
|
@ -150,16 +144,11 @@ class MassManagementMixin(MixinMeta):
|
||||||
query = _query.parsed
|
query = _query.parsed
|
||||||
apply = query["add"] + query["remove"]
|
apply = query["add"] + query["remove"]
|
||||||
if not await self.all_are_valid_roles(ctx, *apply):
|
if not await self.all_are_valid_roles(ctx, *apply):
|
||||||
await ctx.send(
|
await ctx.send("Either you or I don't have the required permissions " "or position in the hierarchy.")
|
||||||
"Either you or I don't have the required permissions "
|
|
||||||
"or position in the hierarchy."
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
for user in users:
|
for user in users:
|
||||||
await self.update_roles_atomically(
|
await self.update_roles_atomically(who=user, give=query["add"], remove=query["remove"])
|
||||||
who=user, give=query["add"], remove=query["remove"]
|
|
||||||
)
|
|
||||||
|
|
||||||
await ctx.tick()
|
await ctx.tick()
|
||||||
|
|
||||||
|
@ -213,9 +202,7 @@ class MassManagementMixin(MixinMeta):
|
||||||
embed = discord.Embed(description=description)
|
embed = discord.Embed(description=description)
|
||||||
if ctx.guild:
|
if ctx.guild:
|
||||||
embed.color = ctx.guild.me.color
|
embed.color = ctx.guild.me.color
|
||||||
await ctx.send(
|
await ctx.send(embed=embed, content=f"Search results for {ctx.author.mention}")
|
||||||
embed=embed, content=f"Search results for {ctx.author.mention}"
|
|
||||||
)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
await self.send_maybe_chunked_csv(ctx, list(members))
|
await self.send_maybe_chunked_csv(ctx, list(members))
|
||||||
|
@ -223,9 +210,7 @@ class MassManagementMixin(MixinMeta):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def send_maybe_chunked_csv(ctx: GuildContext, members):
|
async def send_maybe_chunked_csv(ctx: GuildContext, members):
|
||||||
chunk_size = 75000
|
chunk_size = 75000
|
||||||
chunks = [
|
chunks = [members[i : (i + chunk_size)] for i in range(0, len(members), chunk_size)]
|
||||||
members[i : (i + chunk_size)] for i in range(0, len(members), chunk_size)
|
|
||||||
]
|
|
||||||
|
|
||||||
for part, chunk in enumerate(chunks, 1):
|
for part, chunk in enumerate(chunks, 1):
|
||||||
|
|
||||||
|
@ -246,9 +231,7 @@ class MassManagementMixin(MixinMeta):
|
||||||
"ID": member.id,
|
"ID": member.id,
|
||||||
"Display Name": member.display_name,
|
"Display Name": member.display_name,
|
||||||
"Username#Discrim": str(member),
|
"Username#Discrim": str(member),
|
||||||
"Joined Server": member.joined_at.strftime(fmt)
|
"Joined Server": member.joined_at.strftime(fmt) if member.joined_at else None,
|
||||||
if member.joined_at
|
|
||||||
else None,
|
|
||||||
"Joined Discord": member.created_at.strftime(fmt),
|
"Joined Discord": member.created_at.strftime(fmt),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -262,8 +245,7 @@ class MassManagementMixin(MixinMeta):
|
||||||
filename += f"-part{part}"
|
filename += f"-part{part}"
|
||||||
filename += ".csv"
|
filename += ".csv"
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
content=f"Data for {ctx.author.mention}",
|
content=f"Data for {ctx.author.mention}", files=[discord.File(data, filename=filename)],
|
||||||
files=[discord.File(data, filename=filename)],
|
|
||||||
)
|
)
|
||||||
csvf.close()
|
csvf.close()
|
||||||
data.close()
|
data.close()
|
||||||
|
@ -302,37 +284,26 @@ class MassManagementMixin(MixinMeta):
|
||||||
apply = query["add"] + query["remove"]
|
apply = query["add"] + query["remove"]
|
||||||
if not await self.all_are_valid_roles(ctx, *apply):
|
if not await self.all_are_valid_roles(ctx, *apply):
|
||||||
return await ctx.send(
|
return await ctx.send(
|
||||||
"Either you or I don't have the required permissions "
|
"Either you or I don't have the required permissions " "or position in the hierarchy."
|
||||||
"or position in the hierarchy."
|
|
||||||
)
|
)
|
||||||
|
|
||||||
members = set(ctx.guild.members)
|
members = set(ctx.guild.members)
|
||||||
members = self.search_filter(members, query)
|
members = self.search_filter(members, query)
|
||||||
|
|
||||||
if len(members) > 100:
|
if len(members) > 100:
|
||||||
await ctx.send(
|
await ctx.send("This may take a while given the number of members to update.")
|
||||||
"This may take a while given the number of members to update."
|
|
||||||
)
|
|
||||||
|
|
||||||
async with ctx.typing():
|
async with ctx.typing():
|
||||||
for member in members:
|
for member in members:
|
||||||
try:
|
try:
|
||||||
await self.update_roles_atomically(
|
await self.update_roles_atomically(who=member, give=query["add"], remove=query["remove"])
|
||||||
who=member, give=query["add"], remove=query["remove"]
|
|
||||||
)
|
|
||||||
except RoleManagementException:
|
except RoleManagementException:
|
||||||
log.debug(
|
log.debug(
|
||||||
"Internal filter failure on member id %d guild id %d query %s",
|
"Internal filter failure on member id %d guild id %d query %s", member.id, ctx.guild.id, query,
|
||||||
member.id,
|
|
||||||
ctx.guild.id,
|
|
||||||
query,
|
|
||||||
)
|
)
|
||||||
except discord.HTTPException:
|
except discord.HTTPException:
|
||||||
log.debug(
|
log.debug(
|
||||||
"Unpredicted failure for member id %d in guild id %d query %s",
|
"Unpredicted failure for member id %d in guild id %d query %s", member.id, ctx.guild.id, query,
|
||||||
member.id,
|
|
||||||
ctx.guild.id,
|
|
||||||
query,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
await ctx.tick()
|
await ctx.tick()
|
||||||
|
|
|
@ -26,6 +26,7 @@ TIME_RE_STRING = r"\s?".join(
|
||||||
|
|
||||||
TIME_RE = re.compile(TIME_RE_STRING, re.I)
|
TIME_RE = re.compile(TIME_RE_STRING, re.I)
|
||||||
|
|
||||||
|
|
||||||
def parse_timedelta(argument: str) -> timedelta:
|
def parse_timedelta(argument: str) -> timedelta:
|
||||||
"""
|
"""
|
||||||
Parses a string that contains a time interval and converts it to a timedelta object.
|
Parses a string that contains a time interval and converts it to a timedelta object.
|
||||||
|
@ -37,6 +38,7 @@ def parse_timedelta(argument: str) -> timedelta:
|
||||||
return timedelta(**params)
|
return timedelta(**params)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def parse_seconds(seconds) -> str:
|
def parse_seconds(seconds) -> str:
|
||||||
"""
|
"""
|
||||||
Take seconds and converts it to larger units
|
Take seconds and converts it to larger units
|
||||||
|
@ -77,11 +79,7 @@ class UtilMixin(MixinMeta):
|
||||||
return variation_stripper_re.sub("", s)
|
return variation_stripper_re.sub("", s)
|
||||||
|
|
||||||
async def update_roles_atomically(
|
async def update_roles_atomically(
|
||||||
self,
|
self, *, who: discord.Member, give: List[discord.Role] = None, remove: List[discord.Role] = None,
|
||||||
*,
|
|
||||||
who: discord.Member,
|
|
||||||
give: List[discord.Role] = None,
|
|
||||||
remove: List[discord.Role] = None,
|
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Give and remove roles as a single op with some slight sanity
|
Give and remove roles as a single op with some slight sanity
|
||||||
|
@ -95,10 +93,7 @@ class UtilMixin(MixinMeta):
|
||||||
roles.extend([r for r in give if r not in roles])
|
roles.extend([r for r in give if r not in roles])
|
||||||
if sorted(roles) == sorted(who.roles):
|
if sorted(roles) == sorted(who.roles):
|
||||||
return
|
return
|
||||||
if (
|
if any(r >= me.top_role for r in heirarchy_testing) or not me.guild_permissions.manage_roles:
|
||||||
any(r >= me.top_role for r in heirarchy_testing)
|
|
||||||
or not me.guild_permissions.manage_roles
|
|
||||||
):
|
|
||||||
raise PermissionOrHierarchyException("Can't do that.")
|
raise PermissionOrHierarchyException("Can't do that.")
|
||||||
await who.edit(roles=roles)
|
await who.edit(roles=roles)
|
||||||
|
|
||||||
|
@ -120,10 +115,7 @@ class UtilMixin(MixinMeta):
|
||||||
# Bot allowed
|
# Bot allowed
|
||||||
if not (
|
if not (
|
||||||
guild.me.guild_permissions.manage_roles
|
guild.me.guild_permissions.manage_roles
|
||||||
and (
|
and (guild.me == guild.owner or all(guild.me.top_role > role for role in roles))
|
||||||
guild.me == guild.owner
|
|
||||||
or all(guild.me.top_role > role for role in roles)
|
|
||||||
)
|
|
||||||
):
|
):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -133,9 +125,7 @@ class UtilMixin(MixinMeta):
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
async def is_self_assign_eligible(
|
async def is_self_assign_eligible(self, who: discord.Member, role: discord.Role) -> List[discord.Role]:
|
||||||
self, who: discord.Member, role: discord.Role
|
|
||||||
) -> List[discord.Role]:
|
|
||||||
"""
|
"""
|
||||||
Returns a list of roles to be removed if this one is added, or raises an
|
Returns a list of roles to be removed if this one is added, or raises an
|
||||||
exception
|
exception
|
||||||
|
@ -167,22 +157,14 @@ class UtilMixin(MixinMeta):
|
||||||
req_any_fail = []
|
req_any_fail = []
|
||||||
break
|
break
|
||||||
|
|
||||||
req_all_fail = [
|
req_all_fail = [idx for idx in await self.config.role(role).requires_all() if not who._roles.has(idx)]
|
||||||
idx
|
|
||||||
for idx in await self.config.role(role).requires_all()
|
|
||||||
if not who._roles.has(idx)
|
|
||||||
]
|
|
||||||
|
|
||||||
if req_any_fail or req_all_fail:
|
if req_any_fail or req_all_fail:
|
||||||
raise MissingRequirementsException(
|
raise MissingRequirementsException(miss_all=req_all_fail, miss_any=req_any_fail)
|
||||||
miss_all=req_all_fail, miss_any=req_any_fail
|
|
||||||
)
|
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def check_exclusivity(
|
async def check_exclusivity(self, who: discord.Member, role: discord.Role) -> List[discord.Role]:
|
||||||
self, who: discord.Member, role: discord.Role
|
|
||||||
) -> List[discord.Role]:
|
|
||||||
"""
|
"""
|
||||||
Returns a list of roles to remove, or raises an error
|
Returns a list of roles to remove, or raises an error
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in a new issue