diakonos/stickyroles/stickyroles.py
2024-01-17 00:20:44 -05:00

174 lines
6.3 KiB
Python

import logging
from typing import Literal
import discord
from redbot import VersionInfo, version_info
from redbot.core import Config, checks, commands
from redbot.core.i18n import Translator, cog_i18n
_ = Translator("StickyRoles", __file__)
log = logging.getLogger("red.trusty-cogs.stickyroles")
@cog_i18n(_)
class StickyRoles(commands.Cog):
"""
Reapplies specific roles on join. Rewritten for V3 from
https://github.com/Twentysix26/26-Cogs/blob/master/stickyroles/stickyroles.py
"""
__author__ = ["Twentysix", "TrustyJAID"]
__version__ = "2.0.1"
def __init__(self, bot):
self.bot = bot
self.config = Config.get_conf(self, 1358454876)
self.config.register_guild(sticky_roles=[], to_reapply={})
def format_help_for_context(self, ctx: commands.Context) -> str:
"""
Thanks Sinbad!
"""
pre_processed = super().format_help_for_context(ctx)
return f"{pre_processed}\n\nCog Version: {self.__version__}"
async def red_delete_data_for_user(
self,
*,
requester: Literal["discord_deleted_user", "owner", "user", "user_strict"],
user_id: int,
):
"""
Method for finding users data inside the cog and deleting it.
"""
all_guilds = await self.config.all_guilds()
for guild_id, data in all_guilds.items():
if str(user_id) in data["to_reapply"]:
del data["to_reapply"][str(user_id)]
await self.config.guild_from_id(guild_id).to_reapply.set(data["to_reapply"])
@commands.group(aliases=["stickyrole"])
@checks.admin()
async def stickyroles(self, ctx: commands.Context) -> None:
"""Adds / removes roles to be reapplied on join"""
pass
@stickyroles.command()
async def add(self, ctx: commands.Context, *, role: discord.Role) -> None:
"""Adds role to be reapplied on join"""
guild = ctx.message.guild
sticky_roles = await self.config.guild(guild).sticky_roles()
if not guild.me.top_role.position > role.position:
msg = _(
"I don't have enough permissions to add that "
"role. Remember to take role hierarchy in "
"consideration."
)
await ctx.send(msg)
return
if role.id in sticky_roles:
await ctx.send(role.name + _(" is already in the sticky roles."))
return
sticky_roles.append(role.id)
await self.config.guild(guild).sticky_roles.set(sticky_roles)
await ctx.send(_("That role will now be reapplied on join."))
@stickyroles.command()
async def remove(self, ctx: commands.Context, *, role: discord.Role) -> None:
"""Removes role to be reapplied on join"""
guild = ctx.message.guild
sticky_roles = await self.config.guild(guild).sticky_roles()
if role.id not in sticky_roles:
await ctx.send(_("That role was never added in the first place."))
return
sticky_roles.remove(role.id)
await self.config.guild(guild).sticky_roles.set(sticky_roles)
await ctx.send(_("That role won't be reapplied on join."))
@stickyroles.command()
async def clear(self, ctx: commands.Context) -> None:
"""Removes all sticky roles"""
guild = ctx.message.guild
await self.config.guild(guild).sticky_roles.clear()
await self.config.guild(guild).to_reapply.clear()
await ctx.send(_("All sticky roles have been removed."))
@stickyroles.command(name="list")
async def _list(self, ctx: commands.Context):
"""Lists sticky roles"""
guild = ctx.message.guild
roles = await self.config.guild(guild).sticky_roles()
roles = [guild.get_role(r) for r in await self.config.guild(guild).sticky_roles()]
roles = [r.name for r in roles if r is not None]
if roles:
await ctx.send(_("Sticky roles:\n\n") + ", ".join(roles))
else:
msg = _("No sticky roles. Add some with ") + "`{}stickyroles add`".format(ctx.prefix)
await ctx.send(msg)
@commands.Cog.listener()
async def on_member_remove(self, member: discord.Member):
guild = member.guild
if version_info >= VersionInfo.from_str("3.4.0"):
if await self.bot.cog_disabled_in_guild(self, guild):
return
sticky_roles = await self.config.guild(guild).sticky_roles()
to_reapply = await self.config.guild(guild).to_reapply()
if sticky_roles is None:
return
save = False
for role in member.roles:
if role.id in sticky_roles:
if str(member.id) not in to_reapply:
to_reapply[str(member.id)] = []
to_reapply[str(member.id)].append(role.id)
save = True
if save:
await self.config.guild(guild).to_reapply.set(to_reapply)
@commands.Cog.listener()
async def on_member_join(self, member: discord.Member):
guild = member.guild
if version_info >= VersionInfo.from_str("3.4.0"):
if await self.bot.cog_disabled_in_guild(self, guild):
return
sticky_roles = await self.config.guild(guild).sticky_roles()
to_reapply = await self.config.guild(guild).to_reapply()
if to_reapply is None:
return
if str(member.id) not in to_reapply:
return
to_add = []
for role_id in to_reapply[str(member.id)]:
if role_id not in sticky_roles:
continue
role = discord.utils.get(guild.roles, id=role_id)
if role:
to_add.append(role)
del to_reapply[str(member.id)]
if to_add:
try:
await member.add_roles(*to_add, reason="Sticky roles")
except discord.Forbidden:
log.info(
_("Failed to add roles")
+ _("I lack permissions to do that.")
+ "{} ({})\n{}\n".format(member, member.id, to_add)
)
except discord.HTTPException:
msg = _("Failed to add roles to ") + "{} ({})\n{}".format(
member, member.id, to_add
)
log.exception(msg)
await self.config.guild(guild).to_reapply.set(to_reapply)