mirror of
https://github.com/brandons209/Red-bot-Cogs.git
synced 2024-05-05 04:54:11 +12:00
forgot formmating
This commit is contained in:
parent
217fe41183
commit
54c72d8369
|
@ -28,9 +28,7 @@ class MixinMeta(ABC):
|
|||
raise NotImplementedError()
|
||||
|
||||
@abstractmethod
|
||||
async def is_self_assign_eligible(
|
||||
self, who: discord.Member, role: discord.Role
|
||||
) -> List[discord.Role]:
|
||||
async def is_self_assign_eligible(self, who: discord.Member, role: discord.Role) -> List[discord.Role]:
|
||||
raise NotImplementedError()
|
||||
|
||||
@abstractmethod
|
||||
|
|
|
@ -19,9 +19,7 @@ class RoleSyntaxConverter(NamedTuple):
|
|||
|
||||
@classmethod
|
||||
async def convert(cls, ctx: Context, argument: str):
|
||||
parser = NoExitParser(
|
||||
description="Role management syntax help", add_help=False, allow_abbrev=True
|
||||
)
|
||||
parser = NoExitParser(description="Role management syntax help", add_help=False, allow_abbrev=True)
|
||||
parser.add_argument("--add", nargs="*", dest="add", default=[])
|
||||
parser.add_argument("--remove", nargs="*", dest="remove", default=[])
|
||||
try:
|
||||
|
@ -68,9 +66,7 @@ class ComplexActionConverter(NamedTuple):
|
|||
parser.add_argument("--has-any", nargs="*", dest="any", default=[])
|
||||
parser.add_argument("--has-all", nargs="*", dest="all", default=[])
|
||||
parser.add_argument("--has-none", nargs="*", dest="none", default=[])
|
||||
parser.add_argument(
|
||||
"--has-no-roles", action="store_true", default=False, dest="noroles"
|
||||
)
|
||||
parser.add_argument("--has-no-roles", action="store_true", default=False, dest="noroles")
|
||||
parser.add_argument("--has-perms", nargs="*", dest="hasperm", default=[])
|
||||
parser.add_argument("--any-perm", nargs="*", dest="anyperm", 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("--below", dest="below", type=str, default=None)
|
||||
hum_or_bot = parser.add_mutually_exclusive_group()
|
||||
hum_or_bot.add_argument(
|
||||
"--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-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")
|
||||
|
||||
try:
|
||||
vals = vars(parser.parse_args(shlex.split(argument)))
|
||||
|
@ -131,10 +121,7 @@ class ComplexActionConverter(NamedTuple):
|
|||
|
||||
for attr in ("hasperm", "anyperm", "notperm"):
|
||||
|
||||
vals[attr] = [
|
||||
i.replace("_", " ").lower().replace(" ", "_").replace("server", "guild")
|
||||
for i in vals[attr]
|
||||
]
|
||||
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]):
|
||||
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-all", nargs="*", dest="all", default=[])
|
||||
parser.add_argument("--has-none", nargs="*", dest="none", default=[])
|
||||
parser.add_argument(
|
||||
"--has-no-roles", action="store_true", default=False, dest="noroles"
|
||||
)
|
||||
parser.add_argument("--has-no-roles", action="store_true", default=False, dest="noroles")
|
||||
parser.add_argument("--has-perms", nargs="*", dest="hasperm", default=[])
|
||||
parser.add_argument("--any-perm", nargs="*", dest="anyperm", default=[])
|
||||
parser.add_argument("--not-perm", nargs="*", dest="notperm", default=[])
|
||||
parser.add_argument("--csv", action="store_true", default=False)
|
||||
parser.add_argument(
|
||||
"--has-exactly-nroles", dest="quantity", type=int, default=None
|
||||
)
|
||||
parser.add_argument("--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-less-than-nroles", dest="lt", type=int, default=None)
|
||||
parser.add_argument("--above", dest="above", 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.add_argument(
|
||||
"--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-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")
|
||||
try:
|
||||
vals = vars(parser.parse_args(shlex.split(argument)))
|
||||
except Exception:
|
||||
|
@ -229,10 +206,7 @@ class ComplexSearchConverter(NamedTuple):
|
|||
|
||||
for attr in ("hasperm", "anyperm", "notperm"):
|
||||
|
||||
vals[attr] = [
|
||||
i.replace("_", " ").lower().replace(" ", "_").replace("server", "guild")
|
||||
for i in vals[attr]
|
||||
]
|
||||
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]):
|
||||
raise BadArgument("You gave an invalid permission")
|
||||
|
||||
|
|
|
@ -38,15 +38,13 @@ class CompositeMetaClass(DPYCogMeta, ABCMeta):
|
|||
pass # MRO is fine on __new__ with super() use
|
||||
# no need to manually ensure both get handled here.
|
||||
|
||||
|
||||
MIN_SUB_TIME = 3600
|
||||
SLEEP_TIME = 300
|
||||
|
||||
|
||||
class RoleManagement(
|
||||
UtilMixin,
|
||||
MassManagementMixin,
|
||||
EventMixin,
|
||||
commands.Cog,
|
||||
metaclass=CompositeMetaClass,
|
||||
UtilMixin, MassManagementMixin, EventMixin, commands.Cog, metaclass=CompositeMetaClass,
|
||||
):
|
||||
"""
|
||||
Cog for role management
|
||||
|
@ -61,12 +59,8 @@ class RoleManagement(
|
|||
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.config = Config.get_conf(
|
||||
self, identifier=78631113035100160, force_registration=True
|
||||
)
|
||||
self.config.register_global(
|
||||
handled_variation=False, handled_full_str_emoji=False
|
||||
)
|
||||
self.config = Config.get_conf(self, identifier=78631113035100160, force_registration=True)
|
||||
self.config.register_global(handled_variation=False, handled_full_str_emoji=False)
|
||||
self.config.register_role(
|
||||
exclusive_to=[],
|
||||
requires_any=[],
|
||||
|
@ -77,8 +71,8 @@ class RoleManagement(
|
|||
protected=False,
|
||||
cost=0,
|
||||
subscription=0,
|
||||
subscribed_users={}
|
||||
)#subscribed_users maps str(user.id)-> end time in unix timestamp
|
||||
subscribed_users={},
|
||||
) # subscribed_users maps str(user.id)-> end time in unix timestamp
|
||||
self.config.register_member(roles=[], forbidden=[])
|
||||
self.config.init_custom("REACTROLE", 2)
|
||||
self.config.register_custom(
|
||||
|
@ -155,7 +149,7 @@ class RoleManagement(
|
|||
now_time = time.time()
|
||||
if end_time <= now_time:
|
||||
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]
|
||||
continue
|
||||
# charge user
|
||||
|
@ -172,7 +166,7 @@ class RoleManagement(
|
|||
await bank.withdraw_credits(member, cost)
|
||||
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
|
||||
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."
|
||||
await self.update_roles_atomically(who=member, remove=[role])
|
||||
del role_data["subscribed_users"][user_id]
|
||||
|
@ -202,7 +196,7 @@ class RoleManagement(
|
|||
async with self.config.guild(guild).s_roles() as s_roles:
|
||||
for role_id in reversed(s_roles):
|
||||
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)
|
||||
continue
|
||||
|
||||
|
@ -210,9 +204,7 @@ class RoleManagement(
|
|||
|
||||
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:
|
||||
s_roles.remove(role_id)
|
||||
|
||||
|
@ -226,9 +218,7 @@ class RoleManagement(
|
|||
"""
|
||||
|
||||
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():
|
||||
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.")
|
||||
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:
|
||||
sticky.append(role.id)
|
||||
|
||||
|
@ -292,12 +280,7 @@ class RoleManagement(
|
|||
@checks.admin_or_permissions(manage_guild=True)
|
||||
@commands.command(name="rolebind")
|
||||
async def bind_role_to_reactions(
|
||||
self,
|
||||
ctx: GuildContext,
|
||||
role: discord.Role,
|
||||
channel: discord.TextChannel,
|
||||
msgid: int,
|
||||
emoji: str,
|
||||
self, ctx: GuildContext, role: discord.Role, channel: discord.TextChannel, msgid: int, emoji: str,
|
||||
):
|
||||
"""
|
||||
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):
|
||||
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:
|
||||
message = await channel.fetch_message(msgid)
|
||||
|
@ -334,17 +315,11 @@ class RoleManagement(
|
|||
try:
|
||||
await message.add_reaction(_emoji)
|
||||
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)
|
||||
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(
|
||||
f"Remember, the reactions only function according to "
|
||||
|
@ -356,21 +331,15 @@ class RoleManagement(
|
|||
@commands.bot_has_permissions(manage_roles=True)
|
||||
@checks.admin_or_permissions(manage_guild=True)
|
||||
@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
|
||||
"""
|
||||
|
||||
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()
|
||||
|
||||
@commands.guild_only()
|
||||
|
@ -392,12 +361,7 @@ class RoleManagement(
|
|||
|
||||
use_embeds = await ctx.embed_requested()
|
||||
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:
|
||||
|
@ -408,9 +372,7 @@ class RoleManagement(
|
|||
|
||||
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
|
||||
if use_embeds:
|
||||
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."
|
||||
)
|
||||
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}"
|
||||
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}"
|
||||
if rsets["exclusive_to"]:
|
||||
rstring = ", ".join(
|
||||
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}"
|
||||
)
|
||||
rstring = ", ".join(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}"
|
||||
if rsets["cost"]:
|
||||
curr = await bank.get_currency_name(ctx.guild)
|
||||
cost = rsets["cost"]
|
||||
|
@ -462,9 +416,7 @@ class RoleManagement(
|
|||
await ctx.send(page)
|
||||
|
||||
@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.
|
||||
Cost must be a number greater than 0.
|
||||
|
@ -477,9 +429,7 @@ class RoleManagement(
|
|||
"""
|
||||
|
||||
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:
|
||||
return await ctx.send_help()
|
||||
|
@ -507,9 +457,7 @@ class RoleManagement(
|
|||
(etc)
|
||||
"""
|
||||
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()
|
||||
|
||||
if role_cost == 0:
|
||||
|
@ -532,9 +480,7 @@ class RoleManagement(
|
|||
await ctx.send(f"Subscription set to {parse_seconds(time.total_seconds())}.")
|
||||
|
||||
@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.
|
||||
"""
|
||||
|
@ -546,9 +492,7 @@ class RoleManagement(
|
|||
await ctx.tick()
|
||||
|
||||
@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.
|
||||
"""
|
||||
|
@ -572,9 +516,7 @@ class RoleManagement(
|
|||
|
||||
for role in _roles:
|
||||
async with self.config.role(role).exclusive_to() as ex_list:
|
||||
ex_list.extend(
|
||||
[r.id for r in _roles if r != role and r.id not in ex_list]
|
||||
)
|
||||
ex_list.extend([r.id for r in _roles if r != role and r.id not in ex_list])
|
||||
await ctx.tick()
|
||||
|
||||
@rgroup.command(name="unexclusive")
|
||||
|
@ -595,20 +537,14 @@ class RoleManagement(
|
|||
await ctx.tick()
|
||||
|
||||
@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
|
||||
"""
|
||||
|
||||
if sticky is None:
|
||||
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)
|
||||
if sticky:
|
||||
|
@ -619,7 +555,7 @@ class RoleManagement(
|
|||
|
||||
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")
|
||||
async def reqall(self, ctx: GuildContext, role: discord.Role, *roles: discord.Role):
|
||||
"""
|
||||
|
@ -645,9 +581,7 @@ class RoleManagement(
|
|||
await ctx.tick()
|
||||
|
||||
@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)
|
||||
|
||||
|
@ -657,18 +591,14 @@ class RoleManagement(
|
|||
if removable is None:
|
||||
is_removable = await self.config.role(role).self_removable()
|
||||
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 ctx.tick()
|
||||
|
||||
@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
|
||||
|
||||
|
@ -680,9 +610,7 @@ class RoleManagement(
|
|||
if assignable is None:
|
||||
is_assignable = await self.config.role(role).self_role()
|
||||
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)
|
||||
|
@ -778,7 +706,8 @@ class RoleManagement(
|
|||
for role, (cost, sub) in sorted(data.items(), key=lambda kv: kv[1]):
|
||||
embed.add_field(
|
||||
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
|
||||
if i % 25 == 0:
|
||||
|
@ -802,37 +731,27 @@ class RoleManagement(
|
|||
except RoleManagementException:
|
||||
return
|
||||
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)")
|
||||
else:
|
||||
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:
|
||||
return await ctx.send(
|
||||
"This role doesn't have a cost. Please try again using `[p]srole add`."
|
||||
)
|
||||
return await ctx.send("This role doesn't have a cost. Please try again using `[p]srole add`.")
|
||||
|
||||
free_roles = await self.config.guild(ctx.guild).free_roles()
|
||||
currency_name = await bank.get_currency_name(ctx.guild)
|
||||
for m_role in ctx.author.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 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()
|
||||
return
|
||||
|
||||
try:
|
||||
await bank.withdraw_credits(ctx.author, cost)
|
||||
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:
|
||||
if subscription > 0:
|
||||
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:
|
||||
s.append(role.id)
|
||||
|
||||
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()
|
||||
|
||||
@srole.command(name="add")
|
||||
|
@ -862,24 +779,15 @@ class RoleManagement(
|
|||
except RoleManagementException:
|
||||
return
|
||||
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)")
|
||||
else:
|
||||
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 cost:
|
||||
await ctx.send(
|
||||
"This role is not free. "
|
||||
"Please use `[p]srole buy` if you would like to purchase it."
|
||||
)
|
||||
await ctx.send("This role is not free. " "Please use `[p]srole buy` if you would like to purchase it.")
|
||||
else:
|
||||
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()
|
||||
|
||||
@srole.command(name="remove")
|
||||
|
@ -892,22 +800,18 @@ class RoleManagement(
|
|||
return
|
||||
if await self.config.role(role).self_removable():
|
||||
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:
|
||||
del s[str(ctx.author.id)]
|
||||
except:
|
||||
pass
|
||||
await ctx.tick()
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
|
@ -926,22 +830,16 @@ class RoleManagement(
|
|||
|
||||
channel_id = data.get("channelid", None)
|
||||
if channel_id:
|
||||
link = linkfmt.format(
|
||||
guild_id=role.guild.id,
|
||||
channel_id=channel_id,
|
||||
message_id=message_id,
|
||||
)
|
||||
link = linkfmt.format(guild_id=role.guild.id, channel_id=channel_id, message_id=message_id,)
|
||||
else:
|
||||
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]
|
||||
if emoji_info.isdigit():
|
||||
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:
|
||||
emoji = emoji_info
|
||||
|
@ -949,9 +847,7 @@ class RoleManagement(
|
|||
react_m = f"{role.name} is bound to {emoji} on {link}"
|
||||
yield react_m
|
||||
|
||||
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:
|
||||
str, str, dict
|
||||
|
|
|
@ -84,9 +84,7 @@ class EventMixin(MixinMeta):
|
|||
await member.add_roles(*to_add)
|
||||
|
||||
@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()
|
||||
if not payload.guild_id:
|
||||
return
|
||||
|
@ -127,9 +125,7 @@ class EventMixin(MixinMeta):
|
|||
await self.update_roles_atomically(who=member, give=[role], remove=remove)
|
||||
|
||||
@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()
|
||||
if not payload.guild_id:
|
||||
return
|
||||
|
|
|
@ -4,9 +4,11 @@ from __future__ import annotations
|
|||
class RoleManagementException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class PermissionOrHierarchyException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class MissingRequirementsException(RoleManagementException):
|
||||
def __init__(self, *, miss_any=None, miss_all=None):
|
||||
self.miss_all = miss_all or []
|
||||
|
|
|
@ -88,14 +88,12 @@ class MassManagementMixin(MixinMeta):
|
|||
return False
|
||||
|
||||
if query["anyperm"] and not any(
|
||||
bool(value and perm in query["anyperm"])
|
||||
for perm, value in iter(m.guild_permissions)
|
||||
bool(value and perm in query["anyperm"]) for perm, value in iter(m.guild_permissions)
|
||||
):
|
||||
return False
|
||||
|
||||
if query["notperm"] and any(
|
||||
bool(value and perm in query["notperm"])
|
||||
for perm, value in iter(m.guild_permissions)
|
||||
bool(value and perm in query["notperm"]) for perm, value in iter(m.guild_permissions)
|
||||
):
|
||||
return False
|
||||
|
||||
|
@ -126,11 +124,7 @@ class MassManagementMixin(MixinMeta):
|
|||
|
||||
@mrole.command(name="user")
|
||||
async def mrole_user(
|
||||
self,
|
||||
ctx: GuildContext,
|
||||
users: commands.Greedy[discord.Member],
|
||||
*,
|
||||
_query: RoleSyntaxConverter,
|
||||
self, ctx: GuildContext, users: commands.Greedy[discord.Member], *, _query: RoleSyntaxConverter,
|
||||
) -> None:
|
||||
"""
|
||||
adds/removes roles to one or more users
|
||||
|
@ -150,16 +144,11 @@ class MassManagementMixin(MixinMeta):
|
|||
query = _query.parsed
|
||||
apply = query["add"] + query["remove"]
|
||||
if not await self.all_are_valid_roles(ctx, *apply):
|
||||
await ctx.send(
|
||||
"Either you or I don't have the required permissions "
|
||||
"or position in the hierarchy."
|
||||
)
|
||||
await ctx.send("Either you or I don't have the required permissions " "or position in the hierarchy.")
|
||||
return
|
||||
|
||||
for user in users:
|
||||
await self.update_roles_atomically(
|
||||
who=user, give=query["add"], remove=query["remove"]
|
||||
)
|
||||
await self.update_roles_atomically(who=user, give=query["add"], remove=query["remove"])
|
||||
|
||||
await ctx.tick()
|
||||
|
||||
|
@ -213,9 +202,7 @@ class MassManagementMixin(MixinMeta):
|
|||
embed = discord.Embed(description=description)
|
||||
if ctx.guild:
|
||||
embed.color = ctx.guild.me.color
|
||||
await ctx.send(
|
||||
embed=embed, content=f"Search results for {ctx.author.mention}"
|
||||
)
|
||||
await ctx.send(embed=embed, content=f"Search results for {ctx.author.mention}")
|
||||
|
||||
else:
|
||||
await self.send_maybe_chunked_csv(ctx, list(members))
|
||||
|
@ -223,9 +210,7 @@ class MassManagementMixin(MixinMeta):
|
|||
@staticmethod
|
||||
async def send_maybe_chunked_csv(ctx: GuildContext, members):
|
||||
chunk_size = 75000
|
||||
chunks = [
|
||||
members[i : (i + chunk_size)] for i in range(0, len(members), chunk_size)
|
||||
]
|
||||
chunks = [members[i : (i + chunk_size)] for i in range(0, len(members), chunk_size)]
|
||||
|
||||
for part, chunk in enumerate(chunks, 1):
|
||||
|
||||
|
@ -246,9 +231,7 @@ class MassManagementMixin(MixinMeta):
|
|||
"ID": member.id,
|
||||
"Display Name": member.display_name,
|
||||
"Username#Discrim": str(member),
|
||||
"Joined Server": member.joined_at.strftime(fmt)
|
||||
if member.joined_at
|
||||
else None,
|
||||
"Joined Server": member.joined_at.strftime(fmt) if member.joined_at else None,
|
||||
"Joined Discord": member.created_at.strftime(fmt),
|
||||
}
|
||||
)
|
||||
|
@ -262,8 +245,7 @@ class MassManagementMixin(MixinMeta):
|
|||
filename += f"-part{part}"
|
||||
filename += ".csv"
|
||||
await ctx.send(
|
||||
content=f"Data for {ctx.author.mention}",
|
||||
files=[discord.File(data, filename=filename)],
|
||||
content=f"Data for {ctx.author.mention}", files=[discord.File(data, filename=filename)],
|
||||
)
|
||||
csvf.close()
|
||||
data.close()
|
||||
|
@ -302,37 +284,26 @@ class MassManagementMixin(MixinMeta):
|
|||
apply = query["add"] + query["remove"]
|
||||
if not await self.all_are_valid_roles(ctx, *apply):
|
||||
return 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."
|
||||
)
|
||||
|
||||
members = set(ctx.guild.members)
|
||||
members = self.search_filter(members, query)
|
||||
|
||||
if len(members) > 100:
|
||||
await ctx.send(
|
||||
"This may take a while given the number of members to update."
|
||||
)
|
||||
await ctx.send("This may take a while given the number of members to update.")
|
||||
|
||||
async with ctx.typing():
|
||||
for member in members:
|
||||
try:
|
||||
await self.update_roles_atomically(
|
||||
who=member, give=query["add"], remove=query["remove"]
|
||||
)
|
||||
await self.update_roles_atomically(who=member, give=query["add"], remove=query["remove"])
|
||||
except RoleManagementException:
|
||||
log.debug(
|
||||
"Internal filter failure on member id %d guild id %d query %s",
|
||||
member.id,
|
||||
ctx.guild.id,
|
||||
query,
|
||||
"Internal filter failure on member id %d guild id %d query %s", member.id, ctx.guild.id, query,
|
||||
)
|
||||
except discord.HTTPException:
|
||||
log.debug(
|
||||
"Unpredicted failure for member id %d in guild id %d query %s",
|
||||
member.id,
|
||||
ctx.guild.id,
|
||||
query,
|
||||
"Unpredicted failure for member id %d in guild id %d query %s", member.id, ctx.guild.id, query,
|
||||
)
|
||||
|
||||
await ctx.tick()
|
||||
|
|
|
@ -26,6 +26,7 @@ TIME_RE_STRING = r"\s?".join(
|
|||
|
||||
TIME_RE = re.compile(TIME_RE_STRING, re.I)
|
||||
|
||||
|
||||
def parse_timedelta(argument: str) -> timedelta:
|
||||
"""
|
||||
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 None
|
||||
|
||||
|
||||
def parse_seconds(seconds) -> str:
|
||||
"""
|
||||
Take seconds and converts it to larger units
|
||||
|
@ -77,11 +79,7 @@ class UtilMixin(MixinMeta):
|
|||
return variation_stripper_re.sub("", s)
|
||||
|
||||
async def update_roles_atomically(
|
||||
self,
|
||||
*,
|
||||
who: discord.Member,
|
||||
give: List[discord.Role] = None,
|
||||
remove: List[discord.Role] = None,
|
||||
self, *, 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
|
||||
|
@ -95,10 +93,7 @@ class UtilMixin(MixinMeta):
|
|||
roles.extend([r for r in give if r not in roles])
|
||||
if sorted(roles) == sorted(who.roles):
|
||||
return
|
||||
if (
|
||||
any(r >= me.top_role for r in heirarchy_testing)
|
||||
or not me.guild_permissions.manage_roles
|
||||
):
|
||||
if any(r >= me.top_role for r in heirarchy_testing) or not me.guild_permissions.manage_roles:
|
||||
raise PermissionOrHierarchyException("Can't do that.")
|
||||
await who.edit(roles=roles)
|
||||
|
||||
|
@ -120,10 +115,7 @@ class UtilMixin(MixinMeta):
|
|||
# Bot allowed
|
||||
if not (
|
||||
guild.me.guild_permissions.manage_roles
|
||||
and (
|
||||
guild.me == guild.owner
|
||||
or all(guild.me.top_role > role for role in roles)
|
||||
)
|
||||
and (guild.me == guild.owner or all(guild.me.top_role > role for role in roles))
|
||||
):
|
||||
return False
|
||||
|
||||
|
@ -133,9 +125,7 @@ class UtilMixin(MixinMeta):
|
|||
|
||||
return True
|
||||
|
||||
async def is_self_assign_eligible(
|
||||
self, who: discord.Member, role: discord.Role
|
||||
) -> List[discord.Role]:
|
||||
async def is_self_assign_eligible(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
|
||||
exception
|
||||
|
@ -167,22 +157,14 @@ class UtilMixin(MixinMeta):
|
|||
req_any_fail = []
|
||||
break
|
||||
|
||||
req_all_fail = [
|
||||
idx
|
||||
for idx in await self.config.role(role).requires_all()
|
||||
if not who._roles.has(idx)
|
||||
]
|
||||
req_all_fail = [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:
|
||||
raise MissingRequirementsException(
|
||||
miss_all=req_all_fail, miss_any=req_any_fail
|
||||
)
|
||||
raise MissingRequirementsException(miss_all=req_all_fail, miss_any=req_any_fail)
|
||||
|
||||
return None
|
||||
|
||||
async def check_exclusivity(
|
||||
self, who: discord.Member, role: discord.Role
|
||||
) -> List[discord.Role]:
|
||||
async def check_exclusivity(self, who: discord.Member, role: discord.Role) -> List[discord.Role]:
|
||||
"""
|
||||
Returns a list of roles to remove, or raises an error
|
||||
"""
|
||||
|
|
Loading…
Reference in a new issue