import discord from redbot.core import checks, commands, Config from redbot.core.utils import chat_formatting as chat from redbot.core.utils.menus import menu, DEFAULT_CONTROLS import asyncio from typing import Union, Literal class Rules(commands.Cog): """Simple way to quickly list server and channel rules.""" def __init__(self, bot): self.config = Config.get_conf(self, identifier=875454235448, force_registration=True) self.bot = bot # maps rule number(str) -> rule(str) default_guild = {"rules": {}} default_channel = {"rules": {}} self.config.register_guild(**default_guild) self.config.register_channel(**default_channel) @commands.group(invoke_without_command=True, aliases=["r"]) @commands.guild_only() async def rule(self, ctx, rule_num: int = None): """Display guild and channel rules""" if ctx.invoked_subcommand: return elif rule_num is not None: rules = await self.config.guild(ctx.guild).rules() try: await ctx.send(rules[str(rule_num)]) except KeyError: await ctx.send(chat.error("That rule doesn't exist!")) else: await self.bot.send_help_for(ctx, self.rule) @rule.command(name="list") async def rule_list(self, ctx): """List all guild rules""" rules = await self.config.guild(ctx.guild).rules() embeds = [] rules_keys = sorted([int(r) for r in rules.keys()]) num_rules = len(rules_keys) for i, rule_num in enumerate(rules_keys): embed = discord.Embed(title=f"{ctx.guild.name} rules", colour=ctx.guild.me.colour) embed.add_field(name=f"Rule {rule_num}", value=rules[str(rule_num)]) embed.set_footer(text=f"Page {i+1} of {num_rules}") embeds.append(embed) if not embeds: await ctx.send(chat.warning("No rules defined.")) return await menu(ctx, embeds, DEFAULT_CONTROLS) @rule.group(invoke_without_command=True, name="channel", aliases=["ch", "c"]) async def rule_channel(self, ctx, rule_num: int, channel: Union[discord.TextChannel, discord.VoiceChannel] = None): """ Display channel rule. Defaults to current channel. For voice channels, use the voice channel ID """ if ctx.invoked_subcommand: return if channel: rules = await self.config.channel(channel).rules() else: rules = await self.config.channel(ctx.channel).rules() try: await ctx.send(rules[str(rule_num)]) except KeyError: await ctx.send(chat.error("That rule doesn't exist!")) @rule_channel.command(name="list") async def rule_channel_list(self, ctx, channel: Union[discord.TextChannel, discord.VoiceChannel] = None): """ List all rules for a channel Defaults to current channel. For voice channels, use the voice channel ID """ if channel: rules = await self.config.channel(channel).rules() else: channel = ctx.channel rules = await self.config.channel(channel).rules() embeds = [] rules_keys = sorted([int(r) for r in rules.keys()]) num_rules = len(rules_keys) for i, rule_num in enumerate(rules_keys): embed = discord.Embed(title=f"{channel.name} rules", colour=ctx.guild.me.colour) embed.add_field(name=f"Rule {rule_num}", value=rules[str(rule_num)]) embed.set_footer(text=f"Page {i+1} of {num_rules}") embeds.append(embed) if not embeds: await ctx.send(chat.warning("No rules defined.")) return await menu(ctx, embeds, DEFAULT_CONTROLS) @rule.group(invoke_without_command=True, name="set") @checks.admin_or_permissions(administrator=True) async def rule_set(self, ctx, rule_num: int = None, *, rule: str = None): """ Set a guild rule Will overwrite an existing rule of the same number. """ if ctx.invoked_subcommand: return elif rule_num is not None and rule is not None: async with self.config.guild(ctx.guild).rules() as rules: rules[str(rule_num)] = rule await ctx.tick() elif rule_num is not None: rules = await self.config.guild(ctx.guild).rules() try: await ctx.send(rules[str(rule_num)]) except KeyError: await ctx.send(chat.error("That rule doesn't exist!")) else: await self.bot.send_help_for(ctx, self.rule_set) @rule_set.command(name="channel", aliases=["ch", "c"]) async def rule_set_channel( self, ctx, rule_num: int, channel: Union[discord.TextChannel, discord.VoiceChannel], *, rule: str ): """ Set a channel rule. Can use channel mention or ID. For voice channels, use the voice channel ID. """ async with self.config.channel(channel).rules() as rules: rules[str(rule_num)] = rule await ctx.tick() async def red_delete_data_for_user( self, *, requester: Literal["discord_deleted_user", "owner", "user", "user_strict"], user_id: int, ): pass