async def reactionrole_add(self, ctx: Context, msg: Message, emoji: EmojiConverter, role: Role, reverse: bool, auto_remove: bool): emoji: PartialEmoji if await ReactionRole.get(msg.channel.id, msg.id, str(emoji)): raise CommandError(t.rr_link_already_exists) if not msg.channel.permissions_for(msg.guild.me).add_reactions: raise CommandError(t.rr_link_not_created_no_permissions) check_role_assignable(role) try: await msg.add_reaction(emoji) except Forbidden: raise CommandError(t.could_not_add_reactions) await ReactionRole.create(msg.channel.id, msg.id, str(emoji), role.id, reverse, auto_remove) embed = Embed(title=t.reactionrole, colour=Colors.ReactionRole, description=t.rr_link_created) await reply(ctx, embed=embed) await send_to_changelog( ctx.guild, t.log_rr_link_created(emoji, role.id, msg.jump_url, msg.channel.mention))
async def verification_add(self, ctx: Context, role: Role, reverse: bool = False): """ add verification role if `reverse` is set to `true`, the role is not added but removed during verification. the `verify` command will fail if the user does not have the role. """ check_role_assignable(role) if await db.get(VerificationRole, role_id=role.id) is not None: raise CommandError(t.verification_role_already_set) await VerificationRole.create(role.id, reverse) embed = Embed(title=t.verification, description=t.verification_role_added, colour=Colors.Verification) await reply(ctx, embed=embed) if reverse: await send_to_changelog( ctx.guild, t.log_verification_role_added_reverse(role.name, role.id)) else: await send_to_changelog( ctx.guild, t.log_verification_role_added(role.name, role.id))
async def unmute(self, ctx: Context, user: UserMemberConverter, *, reason: str): """ unmute a user """ user: Union[Member, User] if len(reason) > 900: raise CommandError(t.reason_too_long) mute_role: Role = await get_mute_role(ctx.guild) was_muted = False if isinstance(user, Member) and mute_role in user.roles: was_muted = True check_role_assignable(mute_role) await user.remove_roles(mute_role) async for mute in await db.stream( filter_by(Mute, active=True, member=user.id)): await Mute.deactivate(mute.id, ctx.author.id, reason) was_muted = True if not was_muted: raise UserCommandError(user, t.not_muted) server_embed = Embed(title=t.unmute, description=t.unmuted_response, colour=Colors.ModTools) server_embed.set_author(name=str(user), icon_url=user.display_avatar.url) await reply(ctx, embed=server_embed) await send_to_changelog_mod(ctx.guild, ctx.message, Colors.unmute, t.log_unmuted, user, reason)
async def roles_add(self, ctx: Context, member: Member, *, role: Role): if role in member.roles: raise CommandError(t.role_already_assigned) if not await is_authorized(ctx.author, role, perma=False): raise CommandError(t.role_not_authorized) check_role_assignable(role) await member.add_roles(role) await ctx.message.add_reaction(name_to_emoji["white_check_mark"])
async def roles_perma_remove(self, ctx: Context, member: UserMemberConverter, *, role: Role): member: Union[User, Member] if not await is_authorized(ctx.author, role, perma=True): raise CommandError(t.role_not_authorized) check_role_assignable(role) if not (row := await db.get( PermaRole, member_id=member.id, role_id=role.id)): raise CommandError(t.role_not_assigned)
async def configure_role(ctx: Context, role_name: str, role: Role, check_assignable: bool = False): if check_assignable: check_role_assignable(role) await RoleSettings.set(role_name, role.id) await reply(ctx, t.role_set) await send_to_changelog( ctx.guild, t.log_role_set(Config.ROLES[role_name][0], role.name, role.id))
async def autorole_add(self, ctx: Context, *, role: Role): """ add a role """ if await AutoRole.exists(role.id): raise CommandError(t.ar_already_set) check_role_assignable(role) await AutoRole.add(role.id) await ctx.message.add_reaction(name_to_emoji["white_check_mark"]) await send_to_changelog(ctx.guild, t.log_ar_added(role))
async def roles_auth_add(self, ctx: Context, source: Union[Member, Role], target: Role, allow_perma: bool): if await RoleAuth.check(source.id, target.id): raise CommandError(t.role_auth_already_exists) if isinstance(source, Member) and source.bot: raise CommandError(t.no_auth_for_bots) check_role_assignable(target) await RoleAuth.add(source.id, target.id, allow_perma) await reply(ctx, t.role_auth_created) await send_to_changelog(ctx.guild, t.log_role_auth_created(source, target))
async def mod_loop(self): guild: Guild = self.bot.guilds[0] async for ban in await db.stream(filter_by(Ban, active=True)): if ban.days != -1 and utcnow() >= ban.timestamp + timedelta( days=ban.days): await Ban.deactivate(ban.id) try: user = await self.bot.fetch_user(ban.member) except NotFound: user = ban.member, ban.member_name if isinstance(user, User): try: await guild.unban(user) except Forbidden: await send_alert( guild, t.cannot_unban_user_permissions( user.mention, user.id)) await send_to_changelog_mod(guild, None, Colors.unban, t.log_unbanned, user, t.log_unbanned_expired) mute_role: Optional[Role] = guild.get_role(await RoleSettings.get("mute")) if mute_role is None: return try: check_role_assignable(mute_role) except CommandError: await send_alert( guild, t.cannot_assign_mute_role(mute_role, mute_role.id)) return async for mute in await db.stream(filter_by(Mute, active=True)): if mute.days != -1 and utcnow() >= mute.timestamp + timedelta( days=mute.days): if member := guild.get_member(mute.member): await member.remove_roles(mute_role) else: member = mute.member, mute.member_name await send_to_changelog_mod(guild, None, Colors.unmute, t.log_unmuted, member, t.log_unmuted_expired) await Mute.deactivate(mute.id)
async def roles_remove(self, ctx: Context, member: Member, *, role: Role): if role not in member.roles: raise CommandError(t.role_not_assigned) if not await is_authorized(ctx.author, role, perma=False): raise CommandError(t.role_not_authorized) check_role_assignable(role) if await db.exists( filter_by(PermaRole, member_id=member.id, role_id=role.id)): raise CommandError(t.cannot_remove_perma(await get_prefix())) await member.remove_roles(role) await ctx.message.add_reaction(name_to_emoji["white_check_mark"])
async def register_topics(self, ctx: Context, *, topics: str): """ register one or more new topics """ guild: Guild = ctx.guild names = split_topics(topics) if not names: raise UserInputError valid_chars = set(string.ascii_letters + string.digits + " !#$%&'()+-./:<=>?[\\]^_{|}~") to_be_created: List[str] = [] roles: List[Role] = [] for topic in names: if len(topic) > 100: raise CommandError(t.topic_too_long(topic)) if any(c not in valid_chars for c in topic): raise CommandError(t.topic_invalid_chars(topic)) for role in guild.roles: if role.name.lower() == topic.lower(): break else: to_be_created.append(topic) continue if await db.exists(select(BTPRole).filter_by(role_id=role.id)): raise CommandError(t.topic_already_registered(topic)) check_role_assignable(role) roles.append(role) for name in to_be_created: roles.append(await guild.create_role(name=name, mentionable=True)) for role in roles: await BTPRole.create(role.id) embed = Embed(title=t.betheprofessional, colour=Colors.BeTheProfessional) embed.description = t.topics_registered(cnt=len(roles)) await send_to_changelog( ctx.guild, t.log_topics_registered(cnt=len(roles), topics=", ".join(f"`{r}`" for r in roles))) await reply(ctx, embed=embed)
async def aoc_role_set(self, ctx: Context, *, role: Role): """ configure aoc role """ check_role_assignable(role) old_role: Optional[Role] = ctx.guild.get_role( await AdventOfCodeSettings.role.get()) await AdventOfCodeSettings.role.set(role.id) if old_role: for member in old_role.members: await member.remove_roles(old_role) await self.update_roles(await AOCConfig.get_leaderboard(disable_hook=True)) await reply(ctx, t.role_set) await send_to_changelog(ctx.guild, t.log_role_set(role.name, role.id))
async def roles_perma_add(self, ctx: Context, member: UserMemberConverter, *, role: Role): member: Union[User, Member] if not await is_authorized(ctx.author, role, perma=True): raise CommandError(t.role_not_authorized) check_role_assignable(role) if await db.exists( filter_by(PermaRole, member_id=member.id, role_id=role.id)): raise CommandError(t.role_already_assigned) self.removed_perma_roles.discard((member.id, role.id)) await PermaRole.add(member.id, role.id) if isinstance(member, Member): await member.add_roles(role) await send_to_changelog( ctx.guild, t.added_perma_role(role.mention, member.mention, member)) await ctx.message.add_reaction(name_to_emoji["white_check_mark"])
async def unassign_topics(self, ctx: Context, *, topics: str): """ remove one or more topics (use * to remove all topics) """ member: Member = ctx.author if topics.strip() == "*": roles: List[Role] = await list_topics(ctx.guild) else: roles: List[Role] = await parse_topics(ctx.guild, topics, ctx.author) roles = [r for r in roles if r in member.roles] for role in roles: check_role_assignable(role) await member.remove_roles(*roles, atomic=False) embed = Embed(title=t.betheprofessional, colour=Colors.BeTheProfessional) embed.description = t.topics_removed(cnt=len(roles)) await reply(ctx, embed=embed)
async def assign_topics(self, ctx: Context, *, topics: str): """ add one or more topics (comma separated) you are interested in """ member: Member = ctx.author roles: List[Role] = [ r for r in await parse_topics(ctx.guild, topics, ctx.author) if r not in member.roles ] for role in roles: check_role_assignable(role) await member.add_roles(*roles, atomic=False) embed = Embed(title=t.betheprofessional, colour=Colors.BeTheProfessional) embed.description = t.topics_added(cnt=len(roles)) if not roles: embed.colour = Colors.error await reply(ctx, embed=embed)
async def on_member_join(self, member: Member): roles: list[Role] = [] invalid: list[Role] = [] role: Role for role in map(member.guild.get_role, await AutoRole.all()): if not role: continue try: check_role_assignable(role) except CommandError: invalid.append(role) else: roles.append(role) await member.add_roles(*roles) if invalid: raise PermissionError( member.guild, t.cannot_assign(cnt=len(invalid), member=member, roles=", ".join(role.mention for role in invalid)), )
for topic in names: for role in guild.roles: if role.name.lower() == topic.lower(): break else: raise CommandError(t.topic_not_registered(topic)) if (btp_role := await db.first( select(BTPRole).filter_by(role_id=role.id))) is None: raise CommandError(t.topic_not_registered(topic)) roles.append(role) btp_roles.append(btp_role) for role, btp_role in zip(roles, btp_roles): if delete_roles: check_role_assignable(role) await role.delete() await db.delete(btp_role) embed = Embed(title=t.betheprofessional, colour=Colors.BeTheProfessional) embed.description = t.topics_unregistered(cnt=len(roles)) await send_to_changelog( ctx.guild, t.log_topics_unregistered(cnt=len(roles), topics=", ".join(f"`{r}`" for r in roles))) await send_long_embed(ctx, embed) class BeTheProfessionalCog(Cog, name="BeTheProfessional"): CONTRIBUTORS = [ Contributor.Defelo, Contributor.wolflu, Contributor.MaxiHuHe04,
async def mute(self, ctx: Context, user: UserMemberConverter, days: DurationConverter, *, reason: str): """ mute a user set days to `inf` for a permanent mute """ user: Union[Member, User] days: Optional[int] if len(reason) > 900: raise CommandError(t.reason_too_long) mute_role: Role = await get_mute_role(ctx.guild) if user == self.bot.user or await is_teamler(user): raise UserCommandError(user, t.cannot_mute) if isinstance(user, Member): check_role_assignable(mute_role) await user.add_roles(mute_role) await user.move_to(None) active_mutes: List[Mute] = await db.all( filter_by(Mute, active=True, member=user.id)) for mute in active_mutes: if mute.days == -1: raise UserCommandError(user, t.already_muted) ts = mute.timestamp + timedelta(days=mute.days) if days is not None and utcnow() + timedelta(days=days) <= ts: raise UserCommandError(user, t.already_muted) for mute in active_mutes: await Mute.upgrade(mute.id, ctx.author.id) user_embed = Embed(title=t.mute, colour=Colors.ModTools) server_embed = Embed(title=t.mute, description=t.muted_response, colour=Colors.ModTools) server_embed.set_author(name=str(user), icon_url=user.display_avatar.url) if days is not None: await Mute.create(user.id, str(user), ctx.author.id, days, reason, bool(active_mutes)) user_embed.description = t.muted(ctx.author.mention, ctx.guild.name, reason, cnt=days) await send_to_changelog_mod(ctx.guild, ctx.message, Colors.mute, t.log_muted, user, reason, duration=t.log_field.days(cnt=days)) else: await Mute.create(user.id, str(user), ctx.author.id, -1, reason, bool(active_mutes)) user_embed.description = t.muted_inf(ctx.author.mention, ctx.guild.name, reason) await send_to_changelog_mod(ctx.guild, ctx.message, Colors.mute, t.log_muted, user, reason, duration=t.log_field.days_infinity) try: await user.send(embed=user_embed) except (Forbidden, HTTPException): server_embed.description = t.no_dm + "\n\n" + server_embed.description server_embed.colour = Colors.error await reply(ctx, embed=server_embed)
async def verify(self, ctx: Context, *, password: str): correct_password: str = await VerificationSettings.password.get() if correct_password is None: raise CommandError(t.verification_disabled) if not await db.exists(select(VerificationRole)): raise CommandError(t.verification_disabled) if password != correct_password: raise CommandError(t.password_incorrect) guild: Guild = self.bot.guilds[0] member: Member = guild.get_member(ctx.author.id) delay: int = await VerificationSettings.delay.get() if delay != -1 and (utcnow() - member.joined_at).total_seconds() < delay: raise CommandError(t.too_soon) add: List[Role] = [] remove: List[Role] = [] fail = False async for vrole in await db.stream(select(VerificationRole) ): # type: VerificationRole role: Optional[Role] = guild.get_role(vrole.role_id) if role is None: continue if vrole.reverse: if role in member.roles: remove.append(role) else: fail = True elif not vrole.reverse and role not in member.roles: add.append(role) if not add and not remove: raise CommandError(t.already_verified) if fail: raise CommandError(t.verification_failed) invalid = [] for role in add + remove: try: check_role_assignable(role) except CommandError: invalid.append(role) if invalid: await send_alert( member.guild, t.cannot_assign(cnt=len(invalid), member=member, roles=", ".join(role.mention for role in invalid)), ) raise CommandError(t.verification_failed) await member.add_roles(*add) await member.remove_roles(*remove) embed = Embed(title=t.verification, description=t.verified, colour=Colors.Verification) await reply(ctx, embed=embed)