# Member Info Now that we have commands with arguments, lets make them more personal by fetching info about the user who sent the message. A `bg/whoami` command will reply with something like: ``` **Username:** SkyJoshua **Display Name:** SkyJoshua **User ID:** 15652354820931584 **Member ID:** 42170205766156288 **Roles:** Admin, Moderator, Member **Joined Valour:** 01/01/2022 00:00:00 **Bot:** False ``` ### Fetching the member Every `Message` has a `FetchAuthorMemberAsync()` method that returns a `PlanetMember` — the sender's membership on that planet. We always check if it's null before using it. ```c# // Fetch the member object for the message author PlanetMember member = await message.FetchAuthorMemberAsync(); if (member is null) { await channel.SendMessageAsync("Could not find your member info!"); return; } ``` ### Getting the linked User From the `PlanetMember` you can access the global `User` account directly via `member.User`. This gives you their username, ID, join date, and whether they are a bot. ```c# // Get the linked user account User user = member.User; ``` ### Reading member properties Here are the useful properties available on `member` and `user`: | Property | Description | |---|---| | `user.Name` | Their global Valour username | | `member.Nickname` | Their planet-specific nickname (empty if not set) | | `user.Id` | Their global user ID | | `member.Id` | Their member ID on this planet | | `member.Roles` | The list of roles they have on this planet | | `user.TimeJoined` | When they created their Valour account | | `user.Bot` | Whether they are a bot account | ### Handling nicknames A member may or may not have a nickname set on the planet. We fall back to their username when there isn't one. ```c# // Use their nickname if they have one, otherwise fall back to their username string displayName = string.IsNullOrWhiteSpace(member.Nickname) ? user.Name : member.Nickname; ``` ### Getting role names `member.Roles` gives us the list of roles the member has. We can use LINQ to pull out each role's name and join them into a single string. ```c# // Build a comma-separated list of the member's role names string roleNames = string.Join(", ", member.Roles.Select(r => r.Name)); ``` ### Putting it together Here is the full `whoami` command using everything above: ```c# else if (command == "whoami") { // Fetch the member object for the message author PlanetMember member = await message.FetchAuthorMemberAsync(); if (member is null) { await channel.SendMessageAsync("Could not find your member info!"); return; } // Get the linked user account User user = member.User; // Use their nickname if they have one, otherwise fall back to their username string displayName = string.IsNullOrWhiteSpace(member.Nickname) ? user.Name : member.Nickname; // Build a comma-separated list of the member's role names string roleNames = string.Join(", ", member.Roles.Select(r => r.Name)); // Build and send the info reply await channel.SendMessageAsync($@" **Username:** {user.Name} **Display Name:** {displayName} **User ID:** {user.Id} **Member ID:** {member.Id} **Roles:** {roleNames} **Joined Valour:** {user.TimeJoined} **Bot:** {user.Bot} "); } ```

### Full code below ```c# using Valour.Sdk.Client; using Valour.Shared; using DotNetEnv; using Valour.Sdk.Models; using Valour.Shared.Models; ValourClient client = new ValourClient("https://api.valour.gg/"); client.SetupHttpClient(); Env.Load(); string token = Environment.GetEnvironmentVariable("TOKEN") ?? string.Empty; Dictionary channelCache = new(); if (string.IsNullOrWhiteSpace(token)) { Console.WriteLine($"Token invalid. Please make sure you set a valid token in your .env"); return; } TaskResult loginResult = await client.InitializeUser(token); if (!loginResult.Success) { Console.WriteLine($"Login failed: {loginResult.Message}"); } Console.WriteLine($"Logged in as {client.Me.Name} (ID: {client.Me.Id})"); foreach (Planet planet in client.PlanetService.JoinedPlanets) { await planet.EnsureReadyAsync(); await planet.FetchInitialDataAsync(); foreach (Channel chan in planet.Channels) { channelCache[chan.Id] = chan; if (chan.ChannelType == ChannelTypeEnum.PlanetChat) { await chan.OpenWithResult("YourBotName"); } } } client.MessageService.MessageReceived += onMessageReceived; async Task onMessageReceived(Message message) { string prefix = "bg/"; string content = message.Content; if (!channelCache.TryGetValue(message.ChannelId, out var channel)) return; if (!content.StartsWith(prefix)) return; string withoutPrefix = content.Substring(prefix.Length); string[] parts = withoutPrefix.Split(' ', StringSplitOptions.RemoveEmptyEntries); if (parts.Length == 0) return; string command = parts[0].ToLower(); string[] args = parts.Skip(1).ToArray(); if (command == "ping") { await channel.SendMessageAsync("Pong!"); } else if (command == "whoami") { // Fetch the member object for the message author PlanetMember member = await message.FetchAuthorMemberAsync(); if (member is null) { await channel.SendMessageAsync("Could not find your member info!"); return; } // Get the linked user account User user = member.User; // Use their nickname if they have one, otherwise fall back to their username string displayName = string.IsNullOrWhiteSpace(member.Nickname) ? user.Name : member.Nickname; // Build a comma-separated list of the member's role names string roleNames = string.Join(", ", member.Roles.Select(r => r.Name)); // Build and send the info reply await channel.SendMessageAsync($@" **Username:** {user.Name} **Display Name:** {displayName} **User ID:** {user.Id} **Member ID:** {member.Id} **Roles:** {roleNames} **Joined Valour:** {user.TimeJoined} **Bot:** {user.Bot} "); } } await Task.Delay(Timeout.Infinite); ``` --- ## [The Next step is Permission Checking](7.PermissionChecking.md)