1
Fork 0
mirror of https://github.com/allthingslinux/tux.git synced 2024-10-02 16:43:12 +00:00

refactor(info.py): remove unnecessary line of code to improve readability and maintainability

refactor(info.py): simplify command decorators for readability
refactor(info.py): change ctx type from commands.Context[commands.Bot] to commands.Context for simplicity
feat(info.py): add paginated_embed method to handle paginated embeds in a more reusable way
fix(info.py): check if guild exists before proceeding with commands to prevent errors
feat(info.py): add more detailed server and member information to embeds
refactor(info.py): streamline embed creation for cleaner code
refactor(info.py): remove unused _create_embed_desc method
refactor(info.py): update _chunks method to return list of strings for consistency
refactor(info.py): update _add_buttons_to_menu method to return ViewMenu for consistency

refactor: replace individual button addition with loop to improve code readability and maintainability
This commit is contained in:
kzndotsh 2024-08-31 18:04:36 +00:00
parent cd30e811ef
commit ab01455674

View file

@ -9,233 +9,232 @@ class Info(commands.Cog):
def __init__(self, bot: commands.Bot) -> None: def __init__(self, bot: commands.Bot) -> None:
self.bot = bot self.bot = bot
@commands.hybrid_group( @commands.hybrid_group(name="info", aliases=["i"], usage="info <subcommand>")
name="info",
aliases=["i"],
usage="info <subcommand>",
)
async def info(self, ctx: commands.Context[commands.Bot]) -> None: async def info(self, ctx: commands.Context[commands.Bot]) -> None:
""" """
Information commands. Information commands.
Parameters Parameters
---------- ----------
ctx : commands.Context[commands.Bot] ctx : commands.Context
The discord context object. The context object associated with the command.
""" """
if ctx.invoked_subcommand is None: if ctx.invoked_subcommand is None:
await ctx.send_help("info") await ctx.send_help("info")
@info.command( @info.command(name="server", aliases=["s"], usage="info server")
name="server",
aliases=["s"],
usage="info server",
)
async def server(self, ctx: commands.Context[commands.Bot]) -> None: async def server(self, ctx: commands.Context[commands.Bot]) -> None:
""" """
Show information about the server. Show information about the server.
Parameters Parameters
---------- ----------
ctx : commands.Context[commands.Bot] ctx : commands.Context
The discord context object. The context object associated with the command.
""" """
if not ctx.guild:
return
guild = ctx.guild guild = ctx.guild
if not guild:
return
embed = discord.Embed( embed: discord.Embed = (
title=ctx.guild.name, discord.Embed(
description=guild.description or "No description available.", title=guild.name,
color=discord.Color.blurple(), description=guild.description or "No description available.",
color=discord.Color.blurple(),
)
.set_author(name="Server Information", icon_url=guild.icon)
.add_field(name="Owner", value=str(guild.owner.mention) if guild.owner else "Unknown")
.add_field(name="Vanity URL", value=guild.vanity_url_code or "None")
.add_field(name="Boosts", value=guild.premium_subscription_count)
.add_field(name="Text Channels", value=len(guild.text_channels))
.add_field(name="Voice Channels", value=len(guild.voice_channels))
.add_field(name="Forum Channels", value=len(guild.forums))
.add_field(name="Emojis", value=f"{len(guild.emojis)}/{guild.emoji_limit}")
.add_field(name="Stickers", value=f"{len(guild.stickers)}/{guild.sticker_limit}")
.add_field(name="Roles", value=len(guild.roles))
.add_field(name="Humans", value=sum(not member.bot for member in guild.members))
.add_field(name="Bots", value=sum(member.bot for member in guild.members))
.add_field(name="Bans", value=len([entry async for entry in guild.bans(limit=2000)]))
.set_footer(text=f"ID: {guild.id} | Created: {guild.created_at.strftime('%B %d, %Y')}")
) )
embed.set_author(name="Server Information", icon_url=guild.icon)
embed.add_field(name="Owner", value=str(guild.owner.mention) if guild.owner else "Unknown")
embed.add_field(name="Vanity URL", value=guild.vanity_url_code or "None")
embed.add_field(name="Boosts", value=guild.premium_subscription_count)
embed.add_field(name="Text Channels", value=len(guild.text_channels))
embed.add_field(name="Voice Channels", value=len(guild.voice_channels))
embed.add_field(name="Forum Channels", value=len(guild.forums))
embed.add_field(name="Emojis", value=f"{len(guild.emojis)}/{guild.emoji_limit}")
embed.add_field(name="Stickers", value=f"{len(guild.stickers)}/{guild.sticker_limit}")
embed.add_field(name="Roles", value=len(guild.roles))
embed.add_field(name="Humans", value=sum(not member.bot for member in guild.members))
embed.add_field(name="Bots", value=sum(member.bot for member in guild.members))
embed.add_field(name="Bans", value=len([entry async for entry in guild.bans(limit=2000)]))
embed.set_footer(text=f"ID: {guild.id} | Created: {guild.created_at.strftime('%B %d, %Y')}")
await ctx.send(embed=embed) await ctx.send(embed=embed)
@info.command( @info.command(name="member", aliases=["m", "user", "u"], usage="info member [member]")
name="member",
aliases=["m", "user", "u"],
usage="info member [member]",
)
async def member(self, ctx: commands.Context[commands.Bot], member: discord.Member) -> None: async def member(self, ctx: commands.Context[commands.Bot], member: discord.Member) -> None:
""" """
Show information about a member. Show information about a member.
Parameters Parameters
---------- ----------
ctx : commands.Context[commands.Bot] ctx : commands.Context
The discord context object. The context object associated with the command.
member : discord.Member member : discord.Member
The member to get information about. The member to get information about.
""" """
embed: discord.Embed = (
bot_status = "" if member.bot else "" discord.Embed(
joined = discord.utils.format_dt(member.joined_at, "R") if member.joined_at else "Unknown" title=member.display_name,
created = discord.utils.format_dt(member.created_at, "R") if member.created_at else "Unknown" description="Here is some information about the member.",
roles = ", ".join(role.mention for role in member.roles[1:]) if member.roles[1:] else "No roles" color=discord.Color.blurple(),
fetched_member = await self.bot.fetch_user(member.id) )
.set_thumbnail(url=member.display_avatar.url)
embed = discord.Embed( .set_image(
title=member.display_name, url=(await self.bot.fetch_user(member.id)).banner, # Fetched member's banner
description="Here is some information about the member.", )
color=discord.Color.blurple(), .add_field(name="Bot?", value="" if member.bot else "", inline=False)
.add_field(name="Username", value=member.name, inline=False)
.add_field(name="ID", value=str(member.id), inline=False)
.add_field(
name="Joined",
value=discord.utils.format_dt(member.joined_at, "R") if member.joined_at else "Unknown",
inline=False,
)
.add_field(
name="Registered",
value=discord.utils.format_dt(member.created_at, "R") if member.created_at else "Unknown",
inline=False,
)
.add_field(
name="Roles",
value=", ".join(role.mention for role in member.roles[1:]) if member.roles[1:] else "No roles",
inline=False,
)
) )
embed.set_thumbnail(url=member.display_avatar.url)
embed.set_image(url=fetched_member.banner)
embed.add_field(name="Bot?", value=bot_status, inline=False)
embed.add_field(name="Username", value=member.name, inline=False)
embed.add_field(name="ID", value=str(member.id), inline=False)
embed.add_field(name="Joined", value=joined, inline=False)
embed.add_field(name="Registered", value=created, inline=False)
embed.add_field(name="Roles", value=roles, inline=False)
await ctx.send(embed=embed) await ctx.send(embed=embed)
@info.command( @info.command(name="roles", aliases=["r"], usage="info roles")
name="roles",
aliases=["r"],
usage="info roles",
)
async def roles(self, ctx: commands.Context[commands.Bot]) -> None: async def roles(self, ctx: commands.Context[commands.Bot]) -> None:
""" """
List all roles in the server. List all roles in the server.
Parameters Parameters
---------- ----------
ctx : commands.Context[commands.Bot] ctx : commands.Context
The discord context object. The context object associated with the command.
""" """
if not ctx.guild:
return
guild = ctx.guild guild = ctx.guild
roles = [role.mention for role in guild.roles] if not guild:
embed = discord.Embed(
title="Server Roles",
color=discord.Color.blurple(),
)
chunk_size = 32
if not len(roles) > chunk_size:
embed.description = self._create_embed_desc("roles", guild.name, roles)
await ctx.send(embed=embed)
return return
chunks = self._chunks(iter(roles), chunk_size) roles: list[str] = [role.mention for role in guild.roles]
menu = ViewMenu(ctx, menu_type=ViewMenu.TypeEmbed)
for chunk in chunks: await self.paginated_embed(ctx, "Server Roles", "roles", guild.name, roles, 32)
embed = embed.copy()
embed.description = self._create_embed_desc("roles", guild.name, chunk) @info.command(name="emotes", aliases=["e"], usage="info emotes")
menu.add_page(embed)
menu = self._add_buttons_to_menu(menu)
await menu.start()
@info.command(
name="emotes",
aliases=["e"],
usage="info emotes",
)
async def emotes(self, ctx: commands.Context[commands.Bot]) -> None: async def emotes(self, ctx: commands.Context[commands.Bot]) -> None:
""" """
List all emotes in the server. List all emotes in the server.
Parameters Parameters
---------- ----------
ctx : commands.Context[commands.Bot] ctx : commands.Context
The discord context object. The context object associated with the command.
""" """
if not ctx.guild:
return
guild = ctx.guild guild = ctx.guild
emotes: list[str] = [str(emote) for emote in guild.emojis] if not guild:
embed = discord.Embed(
title="Server Emotes",
color=discord.Color.blurple(),
)
chunk_size = 128
if not len(emotes) > chunk_size:
embed.description = self._create_embed_desc("emotes", guild.name, emotes)
await ctx.send(embed=embed)
return return
chunks = self._chunks(iter(emotes), chunk_size) emotes: list[str] = [str(emote) for emote in guild.emojis]
menu = ViewMenu(ctx, menu_type=ViewMenu.TypeEmbed) await self.paginated_embed(ctx, "Server Emotes", "emotes", guild.name, emotes, 128)
for chunk in chunks: async def paginated_embed(
embed = embed.copy() self,
ctx: commands.Context[commands.Bot],
embed.description = self._create_embed_desc("emotes", guild.name, chunk) title: str,
menu.add_page(embed) list_type: str,
guild_name: str,
menu = self._add_buttons_to_menu(menu) items: Iterable[str],
await menu.start() chunk_size: int,
) -> None:
def _chunks[T](self, it: Iterator[T], size: int) -> Generator[list[T], None, None]:
""" """
Split an iterator into chunks of a specified size. Send a paginated embed.
This function takes an iterator and divides it into chunks of a given size.
Any remaining elements that do not fill a complete chunk are included in the
final chunk, which may be smaller than the specified size.
Parameters Parameters
---------- ----------
it : Iterator[T] ctx : commands.Context
The context object associated with the command.
title : str
The title of the embed.
list_type : str
The type of list (e.g., roles, emotes).
guild_name : str
The name of the guild.
items : Iterable[str]
The items to display in the embed.
chunk_size : int
The size of each chunk for pagination.
"""
embed: discord.Embed = discord.Embed(title=title, color=discord.Color.blurple())
chunks: list[list[str]] = list(self._chunks(iter(items), chunk_size))
if not chunks:
embed.description = "No items available."
await ctx.send(embed=embed)
return
menu: ViewMenu = ViewMenu(ctx, menu_type=ViewMenu.TypeEmbed)
for chunk in chunks:
page_embed: discord.Embed = embed.copy()
page_embed.description = f"{list_type.capitalize()} list for {guild_name}:\n{' '.join(chunk)}"
menu.add_page(page_embed)
self._add_buttons_to_menu(menu)
await menu.start()
def _chunks(self, it: Iterator[str], size: int) -> Generator[list[str], None, None]:
"""
Split an iterator into chunks of a specified size.
Parameters
----------
it : Iterator[str]
The input iterator to be split into chunks. The input iterator to be split into chunks.
size : int size : int
The size of each chunk. The size of each chunk.
Yields Yields
------- ------
list[T] List[str]
A list containing a chunk of elements from the input iterator. The last A list containing a chunk of elements from the input iterator. The last
list may contain fewer elements if there are not enough remaining to fill list may contain fewer elements if there are not enough remaining to fill
a complete chunk. a complete chunk.
""" """
chunk: list[T] = [] chunk: list[str] = []
for item in it: for item in it:
chunk.append(item) chunk.append(item)
if len(chunk) == size: if len(chunk) == size:
yield chunk yield chunk
chunk = [] chunk = []
if chunk: # if last chunk has any items if chunk:
yield chunk yield chunk
def _create_embed_desc(self, list_type: str, guild_name: str, items: Iterable[str]) -> str: def _add_buttons_to_menu(self, menu: ViewMenu) -> ViewMenu:
return ( """
f"{list_type.capitalize()} list for {guild_name}:\n {" ".join(items) if items else "No items available."}" Add buttons to the menu.
)
def _add_buttons_to_menu[T: ViewMenu](self, menu: T) -> T: Parameters
menu.add_button(ViewButton.go_to_first_page()) ----------
menu.add_button(ViewButton.back()) menu : ViewMenu
menu.add_button(ViewButton.next()) The menu to add buttons to.
menu.add_button(ViewButton.go_to_last_page())
menu.add_button(ViewButton.end_session()) Returns
-------
ViewMenu
The menu with buttons added.
"""
buttons = [
ViewButton.go_to_first_page(),
ViewButton.back(),
ViewButton.next(),
ViewButton.go_to_last_page(),
ViewButton.end_session(),
]
for button in buttons:
menu.add_button(button)
return menu return menu