diff --git a/disagreement/models.py b/disagreement/models.py index 29a846a..cfef621 100644 --- a/disagreement/models.py +++ b/disagreement/models.py @@ -913,6 +913,31 @@ class Guild: def get_member(self, user_id: str) -> Optional[Member]: return self._members.get(user_id) + def get_member_named(self, name: str) -> Optional[Member]: + """Retrieve a cached member by username or nickname. + + The lookup is case-insensitive and searches both the username and + guild nickname for a match. + + Parameters + ---------- + name: str + The username or nickname to search for. + + Returns + ------- + Optional[Member] + The matching member if found, otherwise ``None``. + """ + + lowered = name.lower() + for member in self._members.values(): + if member.username.lower() == lowered: + return member + if member.nick and member.nick.lower() == lowered: + return member + return None + def get_role(self, role_id: str) -> Optional[Role]: return next((role for role in self.roles if role.id == role_id), None) diff --git a/docs/caching.md b/docs/caching.md index 9a30d45..f1a1c48 100644 --- a/docs/caching.md +++ b/docs/caching.md @@ -4,6 +4,15 @@ Disagreement ships with a simple in-memory cache used by the HTTP and Gateway cl The client automatically caches guilds, channels and users as they are received from events or HTTP calls. You can access cached data through lookup helpers such as `Client.get_guild`. +Once you have a `Guild` object you can look up its cached members. `Guild.get_member` retrieves a member by ID, while `Guild.get_member_named` searches by username or nickname: + +```python +guild = client.get_guild(123456789012345678) +member = guild.get_member_named("Slipstream") +if member: + print(member.id) +``` + The cache can be cleared manually if needed: ```python diff --git a/examples/basic_bot.py b/examples/basic_bot.py index ffbd995..4028d46 100644 --- a/examples/basic_bot.py +++ b/examples/basic_bot.py @@ -121,6 +121,21 @@ class ExampleCog(commands.Cog): # Ensuring this uses commands.Cog f"Executed 'say' command for {ctx.author.username}, saying: {text_to_say}" ) + @commands.command(name="whois") + async def whois(self, ctx: commands.CommandContext, *, name: str): + """Looks up a member by username or nickname using the guild cache.""" + if not ctx.guild: + await ctx.reply("This command can only be used in a guild.") + return + + member = ctx.guild.get_member_named(name) + if member: + await ctx.reply( + f"Found: {member.username}#{member.discriminator} (nick: {member.nick})" + ) + else: + await ctx.reply("Member not found in cache.") + @commands.command(name="quit") async def quit_command(self, ctx: commands.CommandContext): """Shuts down the bot (requires YOUR_USER_ID to be set)."""