Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Expose GetCurrentUser method & missing current user API methods #2574

Merged
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions docs/guides/bearer_token/bearer_token_guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
uid: Guides.BearerToken
title: Working with Bearer token
---

# Working with Bearer token

Some endpoints in Discord API require a Bearer token, which can be obtained through [OAuth2 flow](https://discord.com/developers/docs/topics/oauth2). Discord.Net allows you to interact with these endopoints using [DiscordRestClient].
csmir marked this conversation as resolved.
Show resolved Hide resolved

## Initializing a new instance of the client
[!code-csharp[Initialize DiscordRestClient](samples/rest_client_init.cs)]

## Getting current user

[DiscordRestClient] gets the current user when `LoginAsync()` is called. The user object can be found in `CurrentUser` property.
csmir marked this conversation as resolved.
Show resolved Hide resolved

If you need to fetch the user again `GetGetCurrentUserAsync()` method can be used.
csmir marked this conversation as resolved.
Show resolved Hide resolved

[!code-csharp[Get current user](samples/current_user.cs)]

> [!NOTE]
> Some properies might be `null` depending on which scopes user authed your app with.
csmir marked this conversation as resolved.
Show resolved Hide resolved
> For example: `email` scope is required to fetch current user's email address.

## Fetching current user's guilds

`GetGuildSummariesAsync()` method is used to fetch current user's guilds. Since it returns an `IAsyncEnumerable` you need to call `FlattenAsync()` to get a plain `IEnumerable` containing [RestUserGuild] objects.
csmir marked this conversation as resolved.
Show resolved Hide resolved

[!code-csharp[Get current user's guilds](samples/current_user_guilds.cs)]

> [!WARNING]
> This method requires `guilds` scope

## Fetching current user's guild member object

To fetch the current user's guild member object the `GetCurrentUserGuildMemberAsync()` method can be used.
csmir marked this conversation as resolved.
Show resolved Hide resolved

[!code-csharp[Get current user's guild member](samples/current_user_guild_member.cs)]

> [!WARNING]
> This method requires `guilds.members.read` scope

## Get user connections

`GetConnectionsAsync` method can be used to fetch current user's connections to other platforms.
csmir marked this conversation as resolved.
Show resolved Hide resolved

[!code-csharp[Get current user's connections](samples/current_user_connections.cs)]

> [!WARNING]
> This method requires `connections` scope

## Application role connection

In addition to previous features Discord.Net supports fetching & updating user's application role conection metadata values. `GetUserApplicationRoleConnectionAsync()` returns a [RoleConnection] object of the current user for the given application id.
csmir marked this conversation as resolved.
Show resolved Hide resolved

`ModifyUserApplicationRoleConnectionAsync()` method is used to update current user's role connection metadata values. A new set of values can be created with [RoleConnectionProperties] object.
csmir marked this conversation as resolved.
Show resolved Hide resolved

[!code-csharp[Get current user's connections](samples/app_role_connection.cs)]

> [!WARNING]
> This method requires `role_connections.write` scope



[DiscordRestClient]: xref:Discord.Rest.DiscordRestClient
[RestUserGuild]: xref:Discord.Rest.RestUserGuild
[RoleConnection]: xref:Discord.RoleConnection
[RoleConnectionProperties]: xref:Discord.RoleConnectionProperties
11 changes: 11 additions & 0 deletions docs/guides/bearer_token/samples/app_role_connection.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// fetch application role connection of the current user for the app with provided id.
var roleConnection = await client.GetUserApplicationRoleConnectionAsync(applicationid);

// create a new role connection metadata properties object & set some values.
var properties = new RoleConnectionProperties("Discord.Net Docs", "Cool Coding Guy")
.WithNumber("eaten_cookies", 69)
.WithBool("loves_cookies", true)
.WithDate("last_eaten_cookie", DateTimeOffset.UtcNow);

// update current user's values with the given properties.
await client.ModifyUserApplicationRoleConnectionAsync(applicationId, properties);
5 changes: 5 additions & 0 deletions docs/guides/bearer_token/samples/current_user.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// gets the user object stored in DiscordRestClient.
csmir marked this conversation as resolved.
Show resolved Hide resolved
var user = client.CurrentUser;

// fetches the current user with a REST call & updates the CurrentUser property.
var refreshedUser = await client.GetCurrentUserAsync();
2 changes: 2 additions & 0 deletions docs/guides/bearer_token/samples/current_user_connections.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// fetches current user's connections.
csmir marked this conversation as resolved.
Show resolved Hide resolved
var connections = await client.GetConnectionsAsync();
6 changes: 6 additions & 0 deletions docs/guides/bearer_token/samples/current_user_guild_member.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// fetches the current user's guild member object in a guild with provided id.
var member = await client.GetCurrentUserGuildMemberAsync(guildId);

// fetches the current user's guild member object in a RestUserGuild.
var guild = await client.GetGuildSummariesAsync().FlattenAsync().First();
var member = await guild.GetCurrentUserGuildMemberAsync();
2 changes: 2 additions & 0 deletions docs/guides/bearer_token/samples/current_user_guilds.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// fetches the guilds the current user participate in.
var guilds = await client.GetGuildSummariesAsync().FlattenAsync();
5 changes: 5 additions & 0 deletions docs/guides/bearer_token/samples/rest_client_init.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
using Discord;
using Discord.Rest;

await using var client = new DiscordRestClient();
await client.LoginAsync(TokenType.Bearer, "bearer token obtained through oauth2 flow");
2 changes: 2 additions & 0 deletions docs/guides/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,5 @@
topicUid: Guides.Voice.SendingVoice
- name: Deployment
topicUid: Guides.Deployment
- name: Working with Bearer token
topicUid: Guides.BearerToken
8 changes: 8 additions & 0 deletions src/Discord.Net.Core/Entities/Guilds/IUserGuild.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,13 @@ public interface IUserGuild : IDeletable, ISnowflakeEntity
/// Returns the current user's permissions for this guild.
/// </summary>
GuildPermissions Permissions { get; }

/// <summary>
/// Gets the features for this guild.
/// </summary>
/// <returns>
/// A flags enum containing all the features for the guild.
/// </returns>
GuildFeatures Features { get; }
}
}
2 changes: 2 additions & 0 deletions src/Discord.Net.Rest/API/Common/UserGuild.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,7 @@ internal class UserGuild
public bool Owner { get; set; }
[JsonProperty("permissions"), Int53]
public string Permissions { get; set; }
[JsonProperty("features")]
public GuildFeatures Features { get; set; }
}
}
9 changes: 8 additions & 1 deletion src/Discord.Net.Rest/DiscordRestApiClient.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

using Discord.API.Rest;
using Discord.Net;
using Discord.Net.Converters;
Expand Down Expand Up @@ -2204,6 +2203,14 @@ public async Task<Channel> CreateDMChannelAsync(CreateDMChannelParams args, Requ

return await SendJsonAsync<Channel>("POST", () => "users/@me/channels", args, new BucketIds(), options: options).ConfigureAwait(false);
}

public async Task<GuildMember> GetCurrentUserGuildMember(ulong guildId, RequestOptions options = null)
{
options = RequestOptions.CreateOrClone(options);

var ids = new BucketIds();
return await SendAsync<GuildMember>("GET", () => $"users/@me/guilds/{guildId}/member", ids, options: options).ConfigureAwait(false);
}
#endregion

#region Voice Regions
Expand Down
13 changes: 13 additions & 0 deletions src/Discord.Net.Rest/DiscordRestClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,19 @@ public async Task<RestInteraction> ParseHttpInteractionAsync(string publicKey, s

#endregion

public async Task<RestSelfUser> GetCurrentUserAsync(RequestOptions options = null)
{
var user = await ApiClient.GetMyUserAsync(options);
CurrentUser.Update(user);
return CurrentUser;
}

public async Task<RestGuildUser> GetCurrentUserGuildMemberAsync(ulong guildId, RequestOptions options = null)
{
var user = await ApiClient.GetCurrentUserGuildMember(guildId, options);
return RestGuildUser.Create(this, null, user, guildId);
}

public async Task<RestApplication> GetApplicationInfoAsync(RequestOptions options = null)
{
return _applicationInfo ??= await ClientHelper.GetApplicationInfoAsync(this, options).ConfigureAwait(false);
Expand Down
10 changes: 10 additions & 0 deletions src/Discord.Net.Rest/Entities/Guilds/RestUserGuild.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public class RestUserGuild : RestEntity<ulong>, IUserGuild
public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id);
/// <inheritdoc />
public string IconUrl => CDN.GetGuildIconUrl(Id, _iconId);
/// <inheritdoc />
public GuildFeatures Features { get; private set; }

internal RestUserGuild(BaseDiscordClient discord, ulong id)
: base(discord, id)
Expand All @@ -39,12 +41,20 @@ internal void Update(Model model)
IsOwner = model.Owner;
Name = model.Name;
Permissions = new GuildPermissions(model.Permissions);
Features = model.Features;
}

public async Task LeaveAsync(RequestOptions options = null)
{
await Discord.ApiClient.LeaveGuildAsync(Id, options).ConfigureAwait(false);
}

public async Task<RestGuildUser> GetCurrentUserGuildMemberAsync(RequestOptions options = null)
{
var user = await Discord.ApiClient.GetCurrentUserGuildMember(Id, options);
return RestGuildUser.Create(Discord, null, user, Id);
}

/// <inheritdoc />
public async Task DeleteAsync(RequestOptions options = null)
{
Expand Down