Browse Source

Finished command permissions as well as bug fixes

pull/1923/head
quin lynch 4 years ago
parent
commit
8e507915e3
26 changed files with 574 additions and 190 deletions
  1. +25
    -13
      src/Discord.Net.Core/Discord.Net.Core.xml
  2. +2
    -2
      src/Discord.Net.Core/Entities/Guilds/PermissionTarget.cs
  3. +5
    -5
      src/Discord.Net.Core/Entities/Interactions/IApplicationCommand.cs
  4. +18
    -0
      src/Discord.Net.Core/Entities/Interactions/SlashCommandBuilder.cs
  5. +12
    -12
      src/Discord.Net.Core/Entities/Permissions/ApplicationCommandPermissions.cs
  6. +6
    -5
      src/Discord.Net.Core/Entities/Permissions/GuildApplicationCommandPermissions.cs
  7. +2
    -0
      src/Discord.Net.Rest/API/Common/ApplicationCommand.cs
  8. +1
    -1
      src/Discord.Net.Rest/API/Common/ApplicationCommandPermissions.cs
  9. +4
    -4
      src/Discord.Net.Rest/API/Common/GuildApplicationCommandPermissions.cs
  10. +1
    -1
      src/Discord.Net.Rest/API/Rest/ModifyGuildApplicationCommandPermissions.cs
  11. +2
    -1
      src/Discord.Net.Rest/ClientHelper.cs
  12. +1
    -1
      src/Discord.Net.Rest/Discord.Net.Rest.csproj
  13. +59
    -0
      src/Discord.Net.Rest/Discord.Net.Rest.xml
  14. +58
    -93
      src/Discord.Net.Rest/DiscordRestApiClient.cs
  15. +9
    -0
      src/Discord.Net.Rest/DiscordRestClient.cs
  16. +14
    -0
      src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs
  17. +24
    -1
      src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs
  18. +202
    -35
      src/Discord.Net.Rest/Entities/Interactions/InteractionHelper.cs
  19. +8
    -1
      src/Discord.Net.Rest/Entities/Interactions/RestApplicationCommand.cs
  20. +35
    -3
      src/Discord.Net.Rest/Entities/Interactions/RestGuildCommand.cs
  21. +3
    -0
      src/Discord.Net.WebSocket/API/Gateway/ApplicationCommandCreatedUpdatedEvent.cs
  22. +27
    -0
      src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml
  23. +24
    -0
      src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs
  24. +10
    -1
      src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketApplicationCommand.cs
  25. +14
    -3
      src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketSlashCommandData.cs
  26. +8
    -8
      src/Discord.Net/Discord.Net.nuspec

+ 25
- 13
src/Discord.Net.Core/Discord.Net.Core.xml View File

@@ -3967,11 +3967,6 @@
The base command model that belongs to an application. see <see href="https://discord.com/developers/docs/interactions/slash-commands#applicationcommand"/>
</summary>
</member>
<member name="P:Discord.IApplicationCommand.Id">
<summary>
Gets the unique id of the command.
</summary>
</member>
<member name="P:Discord.IApplicationCommand.ApplicationId">
<summary>
Gets the unique id of the parent application.
@@ -3987,6 +3982,11 @@
The description of the command.
</summary>
</member>
<member name="P:Discord.IApplicationCommand.DefaultPermission">
<summary>
Whether the command is enabled by default when the app is added to a guild.
</summary>
</member>
<member name="P:Discord.IApplicationCommand.Options">
<summary>
If the option is a subcommand or subcommand group type, this nested options will be the parameters.
@@ -4886,6 +4886,11 @@
Gets or sets the options for this command.
</summary>
</member>
<member name="P:Discord.SlashCommandBuilder.DefaultPermission">
<summary>
Whether the command is enabled by default when the app is added to a guild
</summary>
</member>
<member name="M:Discord.SlashCommandBuilder.Build">
<summary>
Build the current builder into a <see cref="T:Discord.SlashCommandCreationProperties"/> class.
@@ -4908,6 +4913,13 @@
<param name="description">The description of this command.</param>
<returns>The current builder.</returns>
</member>
<member name="M:Discord.SlashCommandBuilder.WithDefaultPermission(System.Boolean)">
<summary>
Sets the default permission of the current command.
</summary>
<param name="value">The default permission value to set.</param>
<returns>The current builder.</returns>
</member>
<member name="M:Discord.SlashCommandBuilder.AddOption(System.String,Discord.ApplicationCommandOptionType,System.String,System.Boolean,System.Boolean,System.Collections.Generic.List{Discord.SlashCommandOptionBuilder},Discord.ApplicationCommandOptionChoiceProperties[])">
<summary>
Adds an option to the current slash command.
@@ -7243,17 +7255,17 @@
Application command permissions allow you to enable or disable commands for specific users or roles within a guild.
</summary>
</member>
<member name="P:Discord.ApplicationCommandPermission.Id">
<member name="P:Discord.ApplicationCommandPermission.TargetId">
<summary>
The id of the role or user.
</summary>
</member>
<member name="P:Discord.ApplicationCommandPermission.Type">
<member name="P:Discord.ApplicationCommandPermission.TargetType">
<summary>
The target of this permission.
</summary>
</member>
<member name="P:Discord.ApplicationCommandPermission.Value">
<member name="P:Discord.ApplicationCommandPermission.Permission">
<summary>
<see langword="true"/> to allow, otherwise <see langword="false"/>.
</summary>
@@ -7525,27 +7537,27 @@
<member name="M:Discord.ChannelPermissions.Modify(System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean},System.Nullable{System.Boolean})">
<summary> Creates a new <see cref="T:Discord.ChannelPermissions"/> from this one, changing the provided non-null permissions. </summary>
</member>
<member name="T:Discord.GuildApplicationCommandPermissions">
<member name="T:Discord.GuildApplicationCommandPermission">
<summary>
Returned when fetching the permissions for a command in a guild.
</summary>
</member>
<member name="P:Discord.GuildApplicationCommandPermissions.Id">
<member name="P:Discord.GuildApplicationCommandPermission.CommandId">
<summary>
The id of the command.
</summary>
</member>
<member name="P:Discord.GuildApplicationCommandPermissions.ApplicationId">
<member name="P:Discord.GuildApplicationCommandPermission.ApplicationId">
<summary>
The id of the application the command belongs to.
</summary>
</member>
<member name="P:Discord.GuildApplicationCommandPermissions.GuildId">
<member name="P:Discord.GuildApplicationCommandPermission.GuildId">
<summary>
The id of the guild.
</summary>
</member>
<member name="P:Discord.GuildApplicationCommandPermissions.Permissions">
<member name="P:Discord.GuildApplicationCommandPermission.Permissions">
<summary>
The permissions for the command in the guild.
</summary>


+ 2
- 2
src/Discord.Net.Core/Entities/Guilds/PermissionTarget.cs View File

@@ -8,10 +8,10 @@ namespace Discord
/// <summary>
/// The target of the permission is a role.
/// </summary>
Role = 0,
Role = 1,
/// <summary>
/// The target of the permission is a user.
/// </summary>
User = 1,
User = 2,
}
}

+ 5
- 5
src/Discord.Net.Core/Entities/Interactions/IApplicationCommand.cs View File

@@ -11,11 +11,6 @@ namespace Discord
/// </summary>
public interface IApplicationCommand : ISnowflakeEntity
{
/// <summary>
/// Gets the unique id of the command.
/// </summary>
ulong Id { get; }

/// <summary>
/// Gets the unique id of the parent application.
/// </summary>
@@ -31,6 +26,11 @@ namespace Discord
/// </summary>
string Description { get; }

/// <summary>
/// Whether the command is enabled by default when the app is added to a guild.
/// </summary>
bool DefaultPermission { get; }

/// <summary>
/// If the option is a subcommand or subcommand group type, this nested options will be the parameters.
/// </summary>


+ 18
- 0
src/Discord.Net.Core/Entities/Interactions/SlashCommandBuilder.cs View File

@@ -82,6 +82,12 @@ namespace Discord
_options = value;
}
}

/// <summary>
/// Whether the command is enabled by default when the app is added to a guild
/// </summary>
public bool DefaultPermission { get; set; } = true;

private string _name { get; set; }
private string _description { get; set; }
private List<SlashCommandOptionBuilder> _options { get; set; }
@@ -96,6 +102,7 @@ namespace Discord
{
Name = this.Name,
Description = this.Description,
DefaultPermission = this.DefaultPermission
};

if (this.Options != null && this.Options.Any())
@@ -135,6 +142,17 @@ namespace Discord
return this;
}

/// <summary>
/// Sets the default permission of the current command.
/// </summary>
/// <param name="value">The default permission value to set.</param>
/// <returns>The current builder.</returns>
public SlashCommandBuilder WithDefaultPermission(bool value)
{
this.DefaultPermission = value;
return this;
}

/// <summary>
/// Adds an option to the current slash command.
/// </summary>


+ 12
- 12
src/Discord.Net.Core/Entities/Permissions/ApplicationCommandPermissions.cs View File

@@ -8,17 +8,17 @@ namespace Discord
/// <summary>
/// The id of the role or user.
/// </summary>
public ulong Id { get; }
public ulong TargetId { get; }

/// <summary>
/// The target of this permission.
/// </summary>
public PermissionTarget Type { get; }
public PermissionTarget TargetType { get; }

/// <summary>
/// <see langword="true"/> to allow, otherwise <see langword="false"/>.
/// </summary>
public bool Value { get; }
public bool Permission { get; }

internal ApplicationCommandPermission() { }

@@ -30,9 +30,9 @@ namespace Discord
/// <param name="allow">The value of this permission.</param>
public ApplicationCommandPermission(ulong targetId, PermissionTarget targetType, bool allow)
{
this.Id = targetId;
this.Type = targetType;
this.Value = allow;
this.TargetId = targetId;
this.TargetType = targetType;
this.Permission = allow;
}

/// <summary>
@@ -42,9 +42,9 @@ namespace Discord
/// <param name="allow">The value of this permission.</param>
public ApplicationCommandPermission(IUser target, bool allow)
{
this.Id = target.Id;
this.Value = allow;
this.Type = PermissionTarget.User;
this.TargetId = target.Id;
this.Permission = allow;
this.TargetType = PermissionTarget.User;
}

/// <summary>
@@ -54,9 +54,9 @@ namespace Discord
/// <param name="allow">The value of this permission.</param>
public ApplicationCommandPermission(IRole target, bool allow)
{
this.Id = target.Id;
this.Value = allow;
this.Type = PermissionTarget.Role;
this.TargetId = target.Id;
this.Permission = allow;
this.TargetType = PermissionTarget.Role;
}
}
}

+ 6
- 5
src/Discord.Net.Core/Entities/Permissions/GuildApplicationCommandPermissions.cs View File

@@ -9,12 +9,13 @@ namespace Discord
/// <summary>
/// Returned when fetching the permissions for a command in a guild.
/// </summary>
public class GuildApplicationCommandPermissions
public class GuildApplicationCommandPermission

{
/// <summary>
/// The id of the command.
/// </summary>
public ulong Id { get; }
public ulong CommandId { get; }

/// <summary>
/// The id of the application the command belongs to.
@@ -31,12 +32,12 @@ namespace Discord
/// </summary>
public IReadOnlyCollection<ApplicationCommandPermission> Permissions { get; }

internal GuildApplicationCommandPermissions(ulong id, ulong appId, ulong guildId, List<ApplicationCommandPermission> permissions)
internal GuildApplicationCommandPermission(ulong commandId, ulong appId, ulong guildId, ApplicationCommandPermission[] permissions)
{
this.Id = id;
this.CommandId = commandId;
this.ApplicationId = appId;
this.GuildId = guildId;
this.Permissions = permissions.ToReadOnlyCollection();
this.Permissions = permissions;
}
}
}

+ 2
- 0
src/Discord.Net.Rest/API/Common/ApplicationCommand.cs View File

@@ -19,5 +19,7 @@ namespace Discord.API
public string Description { get; set; }
[JsonProperty("options")]
public Optional<ApplicationCommandOption[]> Options { get; set; }
[JsonProperty("default_permission")]
public Optional<bool> DefaultPermissions { get; set; }
}
}

+ 1
- 1
src/Discord.Net.Rest/API/Common/ApplicationCommandPermissions.cs View File

@@ -7,7 +7,7 @@ using System.Threading.Tasks;

namespace Discord.API
{
public class ApplicationCommandPermissions
internal class ApplicationCommandPermissions
{
[JsonProperty("id")]
public ulong Id { get; set; }


+ 4
- 4
src/Discord.Net.Rest/API/Common/GuildApplicationCommandPermissions.cs View File

@@ -7,16 +7,16 @@ using System.Threading.Tasks;

namespace Discord.API
{
public class GuildApplicationCommandPermission
internal class GuildApplicationCommandPermission
{
[JsonProperty("id")]
public ulong Id { get; }
public ulong Id { get; set; }

[JsonProperty("application_id")]
public ulong ApplicationId { get; }
public ulong ApplicationId { get; set; }

[JsonProperty("guild_id")]
public ulong GuildId { get; }
public ulong GuildId { get; set; }

[JsonProperty("permissions")]
public API.ApplicationCommandPermissions[] Permissions { get; set; }


+ 1
- 1
src/Discord.Net.Rest/API/Rest/ModifyGuildApplicationCommandPermissions.cs View File

@@ -13,6 +13,6 @@ namespace Discord.API.Rest
public ulong Id { get; set; }

[JsonProperty("permissions")]
public ApplicationCommandPermission[] Permissions { get; set; }
public ApplicationCommandPermissions[] Permissions { get; set; }
}
}

+ 2
- 1
src/Discord.Net.Rest/ClientHelper.cs View File

@@ -206,7 +206,7 @@ namespace Discord.Rest

public static async Task<IReadOnlyCollection<RestGuildCommand>> GetGuildApplicationCommands(BaseDiscordClient client, ulong guildId, RequestOptions options)
{
var response = await client.ApiClient.GetGuildApplicationCommandAsync(guildId, options).ConfigureAwait(false);
var response = await client.ApiClient.GetGuildApplicationCommandsAsync(guildId, options).ConfigureAwait(false);

if (!response.Any())
return new RestGuildCommand[0].ToImmutableArray();
@@ -214,6 +214,7 @@ namespace Discord.Rest
return response.Select(x => RestGuildCommand.Create(client, x, guildId)).ToImmutableArray();
}


public static Task AddRoleAsync(BaseDiscordClient client, ulong guildId, ulong userId, ulong roleId, RequestOptions options = null)
=> client.ApiClient.AddRoleAsync(guildId, userId, roleId, options);


+ 1
- 1
src/Discord.Net.Rest/Discord.Net.Rest.csproj View File

@@ -9,7 +9,7 @@
<TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">netstandard2.0;netstandard2.1</TargetFrameworks>
<PackageIcon>Temporary.png</PackageIcon>
<PackageProjectUrl>https://github.com/Discord-Net-Labs/Discord.Net-Labs</PackageProjectUrl>
<Version>2.4.1</Version>
<Version>2.4.2</Version>
<PackageId>Discord.Net.Labs.Rest</PackageId>
<RepositoryUrl>https://github.com/Discord-Net-Labs/Discord.Net-Labs</RepositoryUrl>
<AssemblyVersion>2.3.4</AssemblyVersion>


+ 59
- 0
src/Discord.Net.Rest/Discord.Net.Rest.xml View File

@@ -2740,6 +2740,27 @@
<member name="M:Discord.Rest.RestGuild.LeaveAsync(Discord.RequestOptions)">
<inheritdoc />
</member>
<member name="M:Discord.Rest.RestGuild.GetSlashCommandsAsync(Discord.RequestOptions)">
<summary>
Gets a collection of slash commands created by the current user in this guild.
</summary>
<param name="options">The options to be used when sending the request.</param>
<returns>
A task that represents the asynchronous get operation. The task result contains a read-only collection of
slash commands created by the current user.
</returns>
</member>
<member name="M:Discord.Rest.RestGuild.GetSlashCommandAsync(System.UInt64,Discord.RequestOptions)">
<summary>
Gets a slash command in the current guild.
</summary>
<param name="id">The unique identifier of the slash command.</param>
<param name="options">The options to be used when sending the request.</param>
<returns>
A task that represents the asynchronous get operation. The task result contains a
slash command created by the current user.
</returns>
</member>
<member name="M:Discord.Rest.RestGuild.GetBansAsync(Discord.RequestOptions)">
<summary>
Gets a collection of all users banned in this guild.
@@ -3378,6 +3399,9 @@
<member name="P:Discord.Rest.RestApplicationCommand.Description">
<inheritdoc/>
</member>
<member name="P:Discord.Rest.RestApplicationCommand.DefaultPermission">
<inheritdoc/>
</member>
<member name="P:Discord.Rest.RestApplicationCommand.Options">
<summary>
The options of this command.
@@ -3391,6 +3415,9 @@
<member name="P:Discord.Rest.RestApplicationCommand.CreatedAt">
<inheritdoc/>
</member>
<member name="M:Discord.Rest.RestApplicationCommand.DeleteAsync(Discord.RequestOptions)">
<inheritdoc/>
</member>
<member name="T:Discord.Rest.RestApplicationCommandChoice">
<summary>
Represents a Rest-based implementation of <see cref="T:Discord.IApplicationCommandOptionChoice"/>.
@@ -3488,6 +3515,38 @@
The modified command
</returns>
</member>
<member name="M:Discord.Rest.RestGuildCommand.GetCommandPermission(Discord.RequestOptions)">
<summary>
Gets this commands permissions inside of the current guild.
</summary>
<param name="options">The options to be used when sending the request.</param>
<returns>
A task that represents the asynchronous get operation. The task result contains a
<see cref="T:Discord.GuildApplicationCommandPermission"/> object defining the permissions of the current slash command.
</returns>
</member>
<member name="M:Discord.Rest.RestGuildCommand.ModifyCommandPermissions(Discord.ApplicationCommandPermission[],Discord.RequestOptions)">
<summary>
Modifies the current command permissions for this guild command.
</summary>
<param name="permissions">The permissions to overwrite.</param>
<param name="options">The options to be used when sending the request.</param>
<returns>
A task that represents the asynchronous modification operation. The task result contains a
<see cref="T:Discord.GuildApplicationCommandPermission"/> object containing the modified permissions.
</returns>
</member>
<member name="M:Discord.Rest.RestGuildCommand.GetGuild(System.Boolean,Discord.RequestOptions)">
<summary>
Gets the guild that this slash command resides in.
</summary>
<param name="withCounts"><see langword="true"/> if you want the approximate member and presence counts for the guild, otherwise <see langword="false"/>.</param>
<param name="options">The options to be used when sending the request.</param>
<returns>
A task that represents the asynchronous get operation. The task result contains a
<see cref="T:Discord.Rest.RestGuild"/>.
</returns>
</member>
<member name="P:Discord.Rest.RestInvite.ChannelName">
<inheritdoc />
</member>


+ 58
- 93
src/Discord.Net.Rest/DiscordRestApiClient.cs View File

@@ -827,54 +827,14 @@ namespace Discord.API

options = RequestOptions.CreateOrClone(options);

try
{
return await SendJsonAsync<ApplicationCommand>("POST", () => $"applications/{this.CurrentUserId}/commands", command, new BucketIds(), options: options).ConfigureAwait(false);
}
catch (HttpException x)
{
if (x.HttpCode == HttpStatusCode.BadRequest)
{
var json = (x.Request as JsonRestRequest).Json;
throw new ApplicationCommandException(json, x);
}

// Re-throw the http exception
throw;
}
return await TrySendApplicationCommand(SendJsonAsync<ApplicationCommand>("POST", () => $"applications/{this.CurrentUserId}/commands", command, new BucketIds(), options: options)).ConfigureAwait(false);
}
public async Task<ApplicationCommand> ModifyGlobalApplicationCommandAsync(ModifyApplicationCommandParams command, ulong commandId, RequestOptions options = null)
{
Preconditions.NotNull(command, nameof(command));

if (command.Name.IsSpecified)
{
Preconditions.AtMost(command.Name.Value.Length, 32, nameof(command.Name));
Preconditions.AtLeast(command.Name.Value.Length, 3, nameof(command.Name));
}
if (command.Description.IsSpecified)
{
Preconditions.AtMost(command.Description.Value.Length, 100, nameof(command.Description));
Preconditions.AtLeast(command.Description.Value.Length, 1, nameof(command.Description));
}

options = RequestOptions.CreateOrClone(options);

try
{
return await SendJsonAsync<ApplicationCommand>("PATCH", () => $"applications/{this.CurrentUserId}/commands/{commandId}", command, new BucketIds(), options: options).ConfigureAwait(false);
}
catch (HttpException x)
{
if (x.HttpCode == HttpStatusCode.BadRequest)
{
var json = (x.Request as JsonRestRequest).Json;
throw new ApplicationCommandException(json, x);
}

// Re-throw the http exception
throw;
}
return await TrySendApplicationCommand(SendJsonAsync<ApplicationCommand>("PATCH", () => $"applications/{this.CurrentUserId}/commands/{commandId}", command, new BucketIds(), options: options)).ConfigureAwait(false);
}
public async Task DeleteGlobalApplicationCommandAsync(ulong commandId, RequestOptions options = null)
{
@@ -883,7 +843,14 @@ namespace Discord.API
await SendAsync("DELETE", () => $"applications/{this.CurrentUserId}/commands/{commandId}", new BucketIds(), options: options).ConfigureAwait(false);
}

public async Task<ApplicationCommand[]> GetGuildApplicationCommandAsync(ulong guildId, RequestOptions options = null)
public async Task<ApplicationCommand[]> BulkOverwriteGlobalApplicationCommands(CreateApplicationCommandParams[] commands, RequestOptions options = null)
{
options = RequestOptions.CreateOrClone(options);

return await TrySendApplicationCommand(SendJsonAsync<ApplicationCommand[]>("PUT", () => $"applications/{this.CurrentUserId}/commands", commands, new BucketIds(), options: options)).ConfigureAwait(false);
}

public async Task<ApplicationCommand[]> GetGuildApplicationCommandsAsync(ulong guildId, RequestOptions options = null)
{
options = RequestOptions.CreateOrClone(options);

@@ -891,49 +858,27 @@ namespace Discord.API

return await SendAsync<ApplicationCommand[]>("GET", () => $"applications/{this.CurrentUserId}/guilds/{guildId}/commands", bucket, options: options).ConfigureAwait(false);
}
public async Task<ApplicationCommand> CreateGuildApplicationCommandAsync(CreateApplicationCommandParams command, ulong guildId, RequestOptions options = null)

public async Task<ApplicationCommand> GetGuildApplicationCommandAsync(ulong guildId, ulong commandId, RequestOptions options = null)
{
Preconditions.NotNull(command, nameof(command));
Preconditions.AtMost(command.Name.Length, 32, nameof(command.Name));
Preconditions.AtLeast(command.Name.Length, 3, nameof(command.Name));
Preconditions.AtMost(command.Description.Length, 100, nameof(command.Description));
Preconditions.AtLeast(command.Description.Length, 1, nameof(command.Description));
options = RequestOptions.CreateOrClone(options);

var bucket = new BucketIds(guildId: guildId);

return await SendAsync<ApplicationCommand>("GET", () => $"applications/{this.CurrentUserId}/guilds/{guildId}/commands/{commandId}", bucket, options: options);
}

public async Task<ApplicationCommand> CreateGuildApplicationCommandAsync(CreateApplicationCommandParams command, ulong guildId, RequestOptions options = null)
{
options = RequestOptions.CreateOrClone(options);

var bucket = new BucketIds(guildId: guildId);

try
{
return await SendJsonAsync<ApplicationCommand>("POST", () => $"applications/{this.CurrentUserId}/guilds/{guildId}/commands", command, bucket, options: options).ConfigureAwait(false);
}
catch (HttpException x)
{
if (x.HttpCode == HttpStatusCode.BadRequest)
{
var json = (x.Request as JsonRestRequest).Json;
throw new ApplicationCommandException(json, x);
}
return await TrySendApplicationCommand(SendJsonAsync<ApplicationCommand>("POST", () => $"applications/{this.CurrentUserId}/guilds/{guildId}/commands", command, bucket, options: options)).ConfigureAwait(false);

// Re-throw the http exception
throw;
}
}
public async Task<ApplicationCommand> ModifyGuildApplicationCommandAsync(ModifyApplicationCommandParams command, ulong guildId, ulong commandId, RequestOptions options = null)
{
Preconditions.NotNull(command, nameof(command));

if (command.Name.IsSpecified)
{
Preconditions.AtMost(command.Name.Value.Length, 32, nameof(command.Name));
Preconditions.AtLeast(command.Name.Value.Length, 3, nameof(command.Name));
}
if (command.Description.IsSpecified)
{
Preconditions.AtMost(command.Description.Value.Length, 100, nameof(command.Description));
Preconditions.AtLeast(command.Description.Value.Length, 1, nameof(command.Description));
}

options = RequestOptions.CreateOrClone(options);

var bucket = new BucketIds(guildId: guildId);
@@ -963,6 +908,15 @@ namespace Discord.API
await SendAsync<ApplicationCommand>("DELETE", () => $"applications/{this.CurrentUserId}/guilds/{guildId}/commands/{commandId}", bucket, options: options).ConfigureAwait(false);
}

public async Task<ApplicationCommand[]> BulkOverwriteGuildApplicationCommands(ulong guildId, CreateApplicationCommandParams[] commands, RequestOptions options = null)
{
options = RequestOptions.CreateOrClone(options);

var bucket = new BucketIds(guildId: guildId);

return await TrySendApplicationCommand(SendJsonAsync<ApplicationCommand[]>("PUT", () => $"applications/{this.CurrentUserId}/guilds/{guildId}/commands", commands, bucket, options: options)).ConfigureAwait(false);
}

//Interaction Responses
public async Task CreateInteractionResponse(InteractionResponse response, ulong interactionId, string interactionToken, RequestOptions options = null)
{
@@ -971,7 +925,7 @@ namespace Discord.API

options = RequestOptions.CreateOrClone(options);

await SendJsonAsync("POST", () => $"interactions/{interactionId}/{interactionToken}/callback", response, new BucketIds(), options: options);
await SendJsonAsync<Message>("POST", () => $"interactions/{interactionId}/{interactionToken}/callback", response, new BucketIds(), options: options);
}
public async Task<Message> GetInteractionResponse(string interactionToken, RequestOptions options = null)
{
@@ -1037,7 +991,7 @@ namespace Discord.API

options = RequestOptions.CreateOrClone(options);

return await SendAsync<GuildApplicationCommandPermission[]>("GET", () => $"/applications/{this.CurrentUserId}/guilds/{guildId}/commands/permissions", new BucketIds(), options: options).ConfigureAwait(false);
return await SendAsync<GuildApplicationCommandPermission[]>("GET", () => $"applications/{this.CurrentUserId}/guilds/{guildId}/commands/permissions", new BucketIds(), options: options).ConfigureAwait(false);
}

public async Task<GuildApplicationCommandPermission> GetGuildApplicationCommandPermission(ulong guildId, ulong commandId, RequestOptions options = null)
@@ -1047,37 +1001,27 @@ namespace Discord.API

options = RequestOptions.CreateOrClone(options);

return await SendAsync<GuildApplicationCommandPermission>("GET", () => $"/applications/{this.CurrentUserId}/guilds/{guildId}/commands/{commandId}/permissions", new BucketIds(), options: options).ConfigureAwait(false);
return await SendAsync<GuildApplicationCommandPermission>("GET", () => $"applications/{this.CurrentUserId}/guilds/{guildId}/commands/{commandId}/permissions", new BucketIds(), options: options).ConfigureAwait(false);
}

public async Task ModifyApplicationCommandPermissions(ApplicationCommandPermissions[] permissions, ulong guildId, ulong commandId, RequestOptions options = null)
public async Task<GuildApplicationCommandPermission> ModifyApplicationCommandPermissions(ApplicationCommandPermissions[] permissions, ulong guildId, ulong commandId, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
Preconditions.NotEqual(commandId, 0, nameof(commandId));

options = RequestOptions.CreateOrClone(options);

await SendJsonAsync("PUT", () => $"/applications/{this.CurrentUserId}/guilds/{guildId}/commands/{commandId}/permissions", permissions, new BucketIds(), options: options).ConfigureAwait(false);
return await SendJsonAsync<GuildApplicationCommandPermission>("PUT", () => $"applications/{this.CurrentUserId}/guilds/{guildId}/commands/{commandId}/permissions", permissions, new BucketIds(), options: options).ConfigureAwait(false);
}

public async Task BatchModifyApplicationCommandPermissions(ModifyGuildApplicationCommandPermissions[] permissions, ulong guildId, RequestOptions options = null)
public async Task<IReadOnlyCollection<GuildApplicationCommandPermission>> BatchModifyApplicationCommandPermissions(ModifyGuildApplicationCommandPermissions[] permissions, ulong guildId, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
Preconditions.NotNull(permissions, nameof(permissions));

options = RequestOptions.CreateOrClone(options);

await SendJsonAsync("PUT", () => $"/applications/{this.CurrentUserId}/guilds/{guildId}/commands/premissions", permissions, new BucketIds(), options: options).ConfigureAwait(false);
}

public async Task BulkOverrideGuildApplicationCommand(API.ApplicationCommand[] commands, ulong guildId, RequestOptions options = null)
{
Preconditions.NotEqual(guildId, 0, nameof(guildId));
Preconditions.NotNull(commands, nameof(commands));

options = RequestOptions.CreateOrClone(options);

await SendJsonAsync("PUT", () => $"/applications/{this.CurrentUserId}/guilds/{guildId}/commands", commands, new BucketIds(), options: options).ConfigureAwait(false);
return await SendJsonAsync<GuildApplicationCommandPermission[]>("PUT", () => $"applications/{this.CurrentUserId}/guilds/{guildId}/commands/permissions", permissions, new BucketIds(), options: options).ConfigureAwait(false);
}

//Guilds
@@ -1772,6 +1716,27 @@ namespace Discord.API
return _serializer.Deserialize<T>(reader);
}

protected async Task<T> TrySendApplicationCommand<T>(Task<T> sendTask)
{
var result = await sendTask.ConfigureAwait(false);

if (sendTask.Exception != null)
{
if (sendTask.Exception.InnerException is HttpException x)
{
if (x.HttpCode == HttpStatusCode.BadRequest)
{
var json = (x.Request as JsonRestRequest).Json;
throw new ApplicationCommandException(json, x);
}
}

throw sendTask.Exception;
}
else
return result;
}

internal class BucketIds
{
public ulong GuildId { get; internal set; }


+ 9
- 0
src/Discord.Net.Rest/DiscordRestClient.cs View File

@@ -106,6 +106,7 @@ namespace Discord.Rest
=> ClientHelper.GetVoiceRegionAsync(this, id, options);
public Task<RestWebhook> GetWebhookAsync(ulong id, RequestOptions options = null)
=> ClientHelper.GetWebhookAsync(this, id, options);

public Task<RestGlobalCommand> CreateGlobalCommand(SlashCommandCreationProperties properties, RequestOptions options = null)
=> InteractionHelper.CreateGlobalCommand(this, properties, options);
public Task<RestGlobalCommand> CreateGlobalCommand(Action<SlashCommandCreationProperties> func, RequestOptions options = null)
@@ -118,6 +119,14 @@ namespace Discord.Rest
=> ClientHelper.GetGlobalApplicationCommands(this, options);
public Task<IReadOnlyCollection<RestGuildCommand>> GetGuildApplicationCommands(ulong guildId, RequestOptions options = null)
=> ClientHelper.GetGuildApplicationCommands(this, guildId, options);
public Task<IReadOnlyCollection<RestGlobalCommand>> BulkOverwriteGlobalCommands(SlashCommandCreationProperties[] commandProperties, RequestOptions options = null)
=> InteractionHelper.BulkOverwriteGlobalCommands(this, commandProperties, options);
public Task<IReadOnlyCollection<RestGuildCommand>> BulkOverwriteGuildCommands(SlashCommandCreationProperties[] commandProperties, ulong guildId, RequestOptions options = null)
=> InteractionHelper.BulkOverwriteGuildCommands(this, guildId, commandProperties, options);
public Task<IReadOnlyCollection<GuildApplicationCommandPermission>> BatchEditGuildCommandPermissions(ulong guildId, IDictionary<ulong, ApplicationCommandPermission[]> permissions, RequestOptions options = null)
=> InteractionHelper.BatchEditGuildCommandPermissionsAsync(this, guildId, permissions, options);


public Task AddRoleAsync(ulong guildId, ulong userId, ulong roleId)
=> ClientHelper.AddRoleAsync(this, guildId, userId, roleId);
public Task RemoveRoleAsync(ulong guildId, ulong userId, ulong roleId)


+ 14
- 0
src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs View File

@@ -270,6 +270,20 @@ namespace Discord.Rest
return RestGuildIntegration.Create(client, guild, model);
}

//Interactions
public static async Task<IReadOnlyCollection<RestGuildCommand>> GetSlashCommandsAsync(IGuild guild, BaseDiscordClient client,
RequestOptions options)
{
var models = await client.ApiClient.GetGuildApplicationCommandsAsync(guild.Id, options);
return models.Select(x => RestGuildCommand.Create(client, x, guild.Id)).ToImmutableArray();
}
public static async Task<RestGuildCommand> GetSlashCommandAsync(IGuild guild, ulong id, BaseDiscordClient client,
RequestOptions options)
{
var model = await client.ApiClient.GetGuildApplicationCommandAsync(guild.Id, id, options);
return RestGuildCommand.Create(client, model, guild.Id);
}

//Invites
public static async Task<IReadOnlyCollection<RestInviteMetadata>> GetInvitesAsync(IGuild guild, BaseDiscordClient client,
RequestOptions options)


+ 24
- 1
src/Discord.Net.Rest/Entities/Guilds/RestGuild.cs View File

@@ -255,7 +255,30 @@ namespace Discord.Rest
public Task LeaveAsync(RequestOptions options = null)
=> GuildHelper.LeaveAsync(this, Discord, options);

//Bans
//Interactions
/// <summary>
/// Gets a collection of slash commands created by the current user in this guild.
/// </summary>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains a read-only collection of
/// slash commands created by the current user.
/// </returns>
public Task<IReadOnlyCollection<RestGuildCommand>> GetSlashCommandsAsync(RequestOptions options = null)
=> GuildHelper.GetSlashCommandsAsync(this, Discord, options);

/// <summary>
/// Gets a slash command in the current guild.
/// </summary>
/// <param name="id">The unique identifier of the slash command.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains a
/// slash command created by the current user.
/// </returns>
public Task<RestGuildCommand> GetSlashCommandAsync(ulong id, RequestOptions options = null)
=> GuildHelper.GetSlashCommandAsync(this, id, Discord, options);

//Bans
/// <summary>
/// Gets a collection of all users banned in this guild.


+ 202
- 35
src/Discord.Net.Rest/Entities/Interactions/InteractionHelper.cs View File

@@ -10,20 +10,20 @@ namespace Discord.Rest
{
internal static class InteractionHelper
{
internal static Task SendInteractionResponse(BaseDiscordClient client, IMessageChannel channel, InteractionResponse response,
public static Task SendInteractionResponse(BaseDiscordClient client, IMessageChannel channel, InteractionResponse response,
ulong interactionId, string interactionToken, RequestOptions options = null)
{
return client.ApiClient.CreateInteractionResponse(response, interactionId, interactionToken, options);
}

internal static async Task<RestInteractionMessage> GetOriginalResponseAsync(BaseDiscordClient client, IMessageChannel channel,
public static async Task<RestInteractionMessage> GetOriginalResponseAsync(BaseDiscordClient client, IMessageChannel channel,
IDiscordInteraction interaction, RequestOptions options = null)
{
var model = await client.ApiClient.GetInteractionResponse(interaction.Token, options).ConfigureAwait(false);
return RestInteractionMessage.Create(client, model, interaction.Token, channel);
}

internal static async Task<RestFollowupMessage> SendFollowupAsync(BaseDiscordClient client, CreateWebhookMessageParams args,
public static async Task<RestFollowupMessage> SendFollowupAsync(BaseDiscordClient client, CreateWebhookMessageParams args,
string token, IMessageChannel channel, RequestOptions options = null)
{
var model = await client.ApiClient.CreateInteractionFollowupMessage(args, token, options).ConfigureAwait(false);
@@ -31,47 +31,128 @@ namespace Discord.Rest
RestFollowupMessage entity = RestFollowupMessage.Create(client, model, token, channel);
return entity;
}
// Global commands
internal static async Task<RestGlobalCommand> CreateGlobalCommand(BaseDiscordClient client,
public static async Task<RestGlobalCommand> CreateGlobalCommand(BaseDiscordClient client,
Action<SlashCommandCreationProperties> func, RequestOptions options = null)
{
var args = new SlashCommandCreationProperties();
func(args);
return await CreateGlobalCommand(client, args, options).ConfigureAwait(false);
}
internal static async Task<RestGlobalCommand> CreateGlobalCommand(BaseDiscordClient client,
SlashCommandCreationProperties args, RequestOptions options = null)
public static async Task<RestGlobalCommand> CreateGlobalCommand(BaseDiscordClient client,
SlashCommandCreationProperties arg, RequestOptions options = null)
{
if (args.Options.IsSpecified)
{
if (args.Options.Value.Count > 10)
throw new ArgumentException("Option count must be 10 or less");
}
Preconditions.NotNullOrEmpty(arg.Name, nameof(arg.Name));
Preconditions.NotNullOrEmpty(arg.Description, nameof(arg.Description));

if (arg.Options.IsSpecified)
Preconditions.AtMost(arg.Options.Value.Count, 25, nameof(arg.Options));

var model = new CreateApplicationCommandParams()
{
Name = args.Name,
Description = args.Description,
Options = args.Options.IsSpecified
? args.Options.Value.Select(x => new Discord.API.ApplicationCommandOption(x)).ToArray()
Name = arg.Name,
Description = arg.Description,
Options = arg.Options.IsSpecified
? arg.Options.Value.Select(x => new Discord.API.ApplicationCommandOption(x)).ToArray()
: Optional<Discord.API.ApplicationCommandOption[]>.Unspecified,
DefaultPermission = args.DefaultPermission.IsSpecified
? args.DefaultPermission.Value
DefaultPermission = arg.DefaultPermission.IsSpecified
? arg.DefaultPermission.Value
: Optional<bool>.Unspecified
};

var cmd = await client.ApiClient.CreateGlobalApplicationCommandAsync(model, options).ConfigureAwait(false);
return RestGlobalCommand.Create(client, cmd);
}
internal static async Task<RestGlobalCommand> ModifyGlobalCommand(BaseDiscordClient client, RestGlobalCommand command,

public static async Task<IReadOnlyCollection<RestGlobalCommand>> BulkOverwriteGlobalCommands(BaseDiscordClient client,
SlashCommandCreationProperties[] args, RequestOptions options = null)
{
Preconditions.NotNull(args, nameof(args));

List<CreateApplicationCommandParams> models = new List<CreateApplicationCommandParams>();

foreach (var arg in args)
{
Preconditions.NotNullOrEmpty(arg.Name, nameof(arg.Name));
Preconditions.NotNullOrEmpty(arg.Description, nameof(arg.Description));

if (arg.Options.IsSpecified)
Preconditions.AtMost(arg.Options.Value.Count, 25, nameof(arg.Options));

var model = new CreateApplicationCommandParams()
{
Name = arg.Name,
Description = arg.Description,
Options = arg.Options.IsSpecified
? arg.Options.Value.Select(x => new Discord.API.ApplicationCommandOption(x)).ToArray()
: Optional<Discord.API.ApplicationCommandOption[]>.Unspecified,
DefaultPermission = arg.DefaultPermission.IsSpecified
? arg.DefaultPermission.Value
: Optional<bool>.Unspecified
};

models.Add(model);
}

var apiModels = await client.ApiClient.BulkOverwriteGlobalApplicationCommands(models.ToArray(), options);

return apiModels.Select(x => RestGlobalCommand.Create(client, x)).ToArray();
}

public static async Task<IReadOnlyCollection<RestGuildCommand>> BulkOverwriteGuildCommands(BaseDiscordClient client, ulong guildId,
SlashCommandCreationProperties[] args, RequestOptions options = null)
{
Preconditions.NotNull(args, nameof(args));

List<CreateApplicationCommandParams> models = new List<CreateApplicationCommandParams>();

foreach (var arg in args)
{
Preconditions.NotNullOrEmpty(arg.Name, nameof(arg.Name));
Preconditions.NotNullOrEmpty(arg.Description, nameof(arg.Description));

if (arg.Options.IsSpecified)
Preconditions.AtMost(arg.Options.Value.Count, 25, nameof(arg.Options));

var model = new CreateApplicationCommandParams()
{
Name = arg.Name,
Description = arg.Description,
Options = arg.Options.IsSpecified
? arg.Options.Value.Select(x => new Discord.API.ApplicationCommandOption(x)).ToArray()
: Optional<Discord.API.ApplicationCommandOption[]>.Unspecified,
DefaultPermission = arg.DefaultPermission.IsSpecified
? arg.DefaultPermission.Value
: Optional<bool>.Unspecified
};

models.Add(model);
}

var apiModels = await client.ApiClient.BulkOverwriteGuildApplicationCommands(guildId, models.ToArray(), options);

return apiModels.Select(x => RestGuildCommand.Create(client, x, guildId)).ToArray();
}

public static async Task<RestGlobalCommand> ModifyGlobalCommand(BaseDiscordClient client, RestGlobalCommand command,
Action<ApplicationCommandProperties> func, RequestOptions options = null)
{
ApplicationCommandProperties args = new ApplicationCommandProperties();
func(args);

if (args.Name.IsSpecified)
{
Preconditions.AtMost(args.Name.Value.Length, 32, nameof(args.Name));
Preconditions.AtLeast(args.Name.Value.Length, 3, nameof(args.Name));
}
if (args.Description.IsSpecified)
{
Preconditions.AtMost(args.Description.Value.Length, 100, nameof(args.Description));
Preconditions.AtLeast(args.Description.Value.Length, 1, nameof(args.Description));
}


if (args.Options.IsSpecified)
{
if (args.Options.Value.Count > 10)
@@ -96,7 +177,7 @@ namespace Discord.Rest
}


internal static async Task DeleteGlobalCommand(BaseDiscordClient client, RestGlobalCommand command, RequestOptions options = null)
public static async Task DeleteGlobalCommand(BaseDiscordClient client, RestGlobalCommand command, RequestOptions options = null)
{
Preconditions.NotNull(command, nameof(command));
Preconditions.NotEqual(command.Id, 0, nameof(command.Id));
@@ -105,7 +186,7 @@ namespace Discord.Rest
}

// Guild Commands
internal static async Task<RestGuildCommand> CreateGuildCommand(BaseDiscordClient client, ulong guildId,
public static async Task<RestGuildCommand> CreateGuildCommand(BaseDiscordClient client, ulong guildId,
Action<SlashCommandCreationProperties> func, RequestOptions options = null)
{
var args = new SlashCommandCreationProperties();
@@ -113,19 +194,23 @@ namespace Discord.Rest

return await CreateGuildCommand(client, guildId, args, options).ConfigureAwait(false);
}
internal static async Task<RestGuildCommand> CreateGuildCommand(BaseDiscordClient client, ulong guildId,
public static async Task<RestGuildCommand> CreateGuildCommand(BaseDiscordClient client, ulong guildId,
SlashCommandCreationProperties args, RequestOptions options = null)
{
Preconditions.NotNullOrEmpty(args.Name, nameof(args.Name));
Preconditions.NotNullOrEmpty(args.Description, nameof(args.Description));

Preconditions.AtMost(args.Name.Length, 32, nameof(args.Name));
Preconditions.AtLeast(args.Name.Length, 3, nameof(args.Name));
Preconditions.AtMost(args.Description.Length, 100, nameof(args.Description));
Preconditions.AtLeast(args.Description.Length, 1, nameof(args.Description));

if (args.Options.IsSpecified)
{
if (args.Options.Value.Count > 10)
throw new ArgumentException("Option count must be 10 or less");

foreach(var item in args.Options.Value)
foreach (var item in args.Options.Value)
{
Preconditions.NotNullOrEmpty(item.Name, nameof(item.Name));
Preconditions.NotNullOrEmpty(item.Description, nameof(item.Description));
@@ -147,12 +232,23 @@ namespace Discord.Rest
var cmd = await client.ApiClient.CreateGuildApplicationCommandAsync(model, guildId, options).ConfigureAwait(false);
return RestGuildCommand.Create(client, cmd, guildId);
}
internal static async Task<RestGuildCommand> ModifyGuildCommand(BaseDiscordClient client, RestGuildCommand command,
public static async Task<RestGuildCommand> ModifyGuildCommand(BaseDiscordClient client, RestGuildCommand command,
Action<ApplicationCommandProperties> func, RequestOptions options = null)
{
ApplicationCommandProperties args = new ApplicationCommandProperties();
func(args);

if (args.Name.IsSpecified)
{
Preconditions.AtMost(args.Name.Value.Length, 32, nameof(args.Name));
Preconditions.AtLeast(args.Name.Value.Length, 3, nameof(args.Name));
}
if (args.Description.IsSpecified)
{
Preconditions.AtMost(args.Description.Value.Length, 100, nameof(args.Description));
Preconditions.AtLeast(args.Description.Value.Length, 1, nameof(args.Description));
}

if (args.Options.IsSpecified)
{
if (args.Options.Value.Count > 10)
@@ -176,15 +272,15 @@ namespace Discord.Rest
return command;
}

internal static async Task DeleteGuildCommand(BaseDiscordClient client, RestGuildCommand command, RequestOptions options = null)
public static async Task DeleteGuildCommand(BaseDiscordClient client, ulong guildId, IApplicationCommand command, RequestOptions options = null)
{
Preconditions.NotNull(command, nameof(command));
Preconditions.NotEqual(command.Id, 0, nameof(command.Id));

await client.ApiClient.DeleteGuildApplicationCommandAsync(command.GuildId, command.Id, options).ConfigureAwait(false);
await client.ApiClient.DeleteGuildApplicationCommandAsync(guildId, command.Id, options).ConfigureAwait(false);
}

internal static async Task<Discord.API.Message> ModifyFollowupMessage(BaseDiscordClient client, RestFollowupMessage message, Action<MessageProperties> func,
public static async Task<Discord.API.Message> ModifyFollowupMessage(BaseDiscordClient client, RestFollowupMessage message, Action<MessageProperties> func,
RequestOptions options = null)
{
var args = new MessageProperties();
@@ -204,10 +300,10 @@ namespace Discord.Rest
return await client.ApiClient.ModifyInteractionFollowupMessage(apiArgs, message.Id, message.Token, options).ConfigureAwait(false);
}

internal static async Task DeleteFollowupMessage(BaseDiscordClient client, RestFollowupMessage message, RequestOptions options = null)
public static async Task DeleteFollowupMessage(BaseDiscordClient client, RestFollowupMessage message, RequestOptions options = null)
=> await client.ApiClient.DeleteInteractionFollowupMessage(message.Id, message.Token, options);

internal static async Task<Discord.API.Message> ModifyInteractionResponse(BaseDiscordClient client, RestInteractionMessage message, Action<MessageProperties> func,
public static async Task<Discord.API.Message> ModifyInteractionResponse(BaseDiscordClient client, RestInteractionMessage message, Action<MessageProperties> func,
RequestOptions options = null)
{
var args = new MessageProperties();
@@ -227,16 +323,87 @@ namespace Discord.Rest
return await client.ApiClient.ModifyInteractionFollowupMessage(apiArgs, message.Id, message.Token, options).ConfigureAwait(false);
}

internal static async Task DeletedInteractionResponse(BaseDiscordClient client, RestInteractionMessage message, RequestOptions options = null)
public static async Task DeletedInteractionResponse(BaseDiscordClient client, RestInteractionMessage message, RequestOptions options = null)
=> await client.ApiClient.DeleteInteractionFollowupMessage(message.Id, message.Token, options);

// Guild permissions
internal static async Task<IReadOnlyCollection<Discord.GuildApplicationCommandPermissions>> GetCommandGuildPermissions(BaseDiscordClient client,
RestGuildCommand command)
public static async Task<IReadOnlyCollection<GuildApplicationCommandPermission>> GetGuildCommandPermissionsAsync(BaseDiscordClient client,
ulong guildId, RequestOptions options)
{
// TODO
return null;
var models = await client.ApiClient.GetGuildApplicationCommandPermissions(guildId, options);
return models.Select(x =>
new GuildApplicationCommandPermission(x.Id, x.ApplicationId, guildId, x.Permissions.Select(
y => new Discord.ApplicationCommandPermission(y.Id, y.Type, y.Permission))
.ToArray())
).ToArray();
}

public static async Task<GuildApplicationCommandPermission> GetGuildCommandPermissionAsync(BaseDiscordClient client,
ulong guildId, ulong commandId, RequestOptions options)
{
var model = await client.ApiClient.GetGuildApplicationCommandPermission(guildId, commandId, options);
return new GuildApplicationCommandPermission(model.Id, model.ApplicationId, guildId, model.Permissions.Select(
y => new ApplicationCommandPermission(y.Id, y.Type, y.Permission)).ToArray());
}

public static async Task<GuildApplicationCommandPermission> ModifyGuildCommandPermissionsAsync(BaseDiscordClient client, ulong guildId, ulong commandId,
ApplicationCommandPermission[] args, RequestOptions options)
{
Preconditions.NotNull(args, nameof(args));
Preconditions.AtMost(args.Length, 10, nameof(args));
Preconditions.GreaterThan(args.Length, 0, nameof(args));

List<ApplicationCommandPermissions> models = new List<ApplicationCommandPermissions>();

foreach(var arg in args)
{
var model = new ApplicationCommandPermissions()
{
Id = arg.TargetId,
Permission = arg.Permission,
Type = arg.TargetType
};

models.Add(model);
}

var apiModel = await client.ApiClient.ModifyApplicationCommandPermissions(models.ToArray(), guildId, commandId, options);

return new GuildApplicationCommandPermission(apiModel.Id, apiModel.ApplicationId, guildId, apiModel.Permissions.Select(
x => new ApplicationCommandPermission(x.Id, x.Type, x.Permission)).ToArray());
}

public static async Task<IReadOnlyCollection<GuildApplicationCommandPermission>> BatchEditGuildCommandPermissionsAsync(BaseDiscordClient client, ulong guildId,
IDictionary<ulong, ApplicationCommandPermission[]> args, RequestOptions options)
{
Preconditions.NotNull(args, nameof(args));
Preconditions.NotEqual(args.Count, 0, nameof(args));

List<ModifyGuildApplicationCommandPermissions> models = new List<ModifyGuildApplicationCommandPermissions>();

foreach(var arg in args)
{
Preconditions.AtMost(arg.Value.Length, 10, nameof(args));

var model = new ModifyGuildApplicationCommandPermissions()
{
Id = arg.Key,
Permissions = arg.Value.Select(x => new ApplicationCommandPermissions()
{
Id = x.TargetId,
Permission = x.Permission,
Type = x.TargetType
}).ToArray()
};

models.Add(model);
}

var apiModels = await client.ApiClient.BatchModifyApplicationCommandPermissions(models.ToArray(), guildId, options);

return apiModels.Select(
x => new GuildApplicationCommandPermission(x.Id, x.ApplicationId, x.GuildId, x.Permissions.Select(
y => new ApplicationCommandPermission(y.Id, y.Type, y.Permission)).ToArray())).ToArray();
}
}
}

+ 8
- 1
src/Discord.Net.Rest/Entities/Interactions/RestApplicationCommand.cs View File

@@ -22,6 +22,9 @@ namespace Discord.Rest
/// <inheritdoc/>
public string Description { get; private set; }

/// <inheritdoc/>
public bool DefaultPermission { get; private set; }

/// <summary>
/// The options of this command.
/// </summary>
@@ -58,14 +61,18 @@ namespace Discord.Rest
this.ApplicationId = model.ApplicationId;
this.Name = model.Name;
this.Description = model.Description;
this.DefaultPermission = model.DefaultPermissions.GetValueOrDefault(true);

this.Options = model.Options.IsSpecified
? model.Options.Value.Select(x => RestApplicationCommandOption.Create(x)).ToImmutableArray()
: null;
}


/// <inheritdoc/>
public abstract Task DeleteAsync(RequestOptions options = null);

IReadOnlyCollection<IApplicationCommandOption> IApplicationCommand.Options => Options;

public virtual Task DeleteAsync(RequestOptions options = null) => throw new NotImplementedException();
}
}

+ 35
- 3
src/Discord.Net.Rest/Entities/Interactions/RestGuildCommand.cs View File

@@ -33,7 +33,7 @@ namespace Discord.Rest

/// <inheritdoc/>
public override async Task DeleteAsync(RequestOptions options = null)
=> await InteractionHelper.DeleteGuildCommand(Discord, this).ConfigureAwait(false);
=> await InteractionHelper.DeleteGuildCommand(Discord, GuildId, this).ConfigureAwait(false);

/// <summary>
/// Modifies this <see cref="RestApplicationCommand"/>.
@@ -46,7 +46,39 @@ namespace Discord.Rest
public async Task<RestGuildCommand> ModifyAsync(Action<ApplicationCommandProperties> func, RequestOptions options = null)
=> await InteractionHelper.ModifyGuildCommand(Discord, this, func, options).ConfigureAwait(false);

public async Task<IReadOnlyCollection<Discord.GuildApplicationCommandPermissions>> GetCommandPermissions()
=> await InteractionHelper.GetCommandGuildPermissions(Discord, this);
/// <summary>
/// Gets this commands permissions inside of the current guild.
/// </summary>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains a
/// <see cref="GuildApplicationCommandPermission"/> object defining the permissions of the current slash command.
/// </returns>
public Task<GuildApplicationCommandPermission> GetCommandPermission(RequestOptions options = null)
=> InteractionHelper.GetGuildCommandPermissionAsync(Discord, this.GuildId, this.Id, options);

/// <summary>
/// Modifies the current command permissions for this guild command.
/// </summary>
/// <param name="permissions">The permissions to overwrite.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous modification operation. The task result contains a
/// <see cref="GuildApplicationCommandPermission"/> object containing the modified permissions.
/// </returns>
public Task<GuildApplicationCommandPermission> ModifyCommandPermissions(ApplicationCommandPermission[] permissions, RequestOptions options = null)
=> InteractionHelper.ModifyGuildCommandPermissionsAsync(Discord, this.GuildId, this.Id, permissions, options);

/// <summary>
/// Gets the guild that this slash command resides in.
/// </summary>
/// <param name="withCounts"><see langword="true"/> if you want the approximate member and presence counts for the guild, otherwise <see langword="false"/>.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains a
/// <see cref="RestGuild"/>.
/// </returns>
public Task<RestGuild> GetGuild(bool withCounts = false, RequestOptions options = null)
=> ClientHelper.GetGuildAsync(this.Discord, this.GuildId, withCounts, options);
}
}

+ 3
- 0
src/Discord.Net.WebSocket/API/Gateway/ApplicationCommandCreatedUpdatedEvent.cs View File

@@ -26,5 +26,8 @@ namespace Discord.API.Gateway

[JsonProperty("options")]
public Optional<List<Discord.API.ApplicationCommandOption>> Options { get; set; }

[JsonProperty("default_permission")]
public Optional<bool> DefaultPermission { get; set; }
}
}

+ 27
- 0
src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml View File

@@ -2843,6 +2843,27 @@
voice regions the guild can access.
</returns>
</member>
<member name="M:Discord.WebSocket.SocketGuild.GetSlashCommandsAsync(Discord.RequestOptions)">
<summary>
Gets a collection of slash commands created by the current user in this guild.
</summary>
<param name="options">The options to be used when sending the request.</param>
<returns>
A task that represents the asynchronous get operation. The task result contains a read-only collection of
slash commands created by the current user.
</returns>
</member>
<member name="M:Discord.WebSocket.SocketGuild.GetSlashCommandAsync(System.UInt64,Discord.RequestOptions)">
<summary>
Gets a slash command in the current guild.
</summary>
<param name="id">The unique identifier of the slash command.</param>
<param name="options">The options to be used when sending the request.</param>
<returns>
A task that represents the asynchronous get operation. The task result contains a
slash command created by the current user.
</returns>
</member>
<member name="M:Discord.WebSocket.SocketGuild.GetInvitesAsync(Discord.RequestOptions)">
<summary>
Gets a collection of all invites in this guild.
@@ -3243,6 +3264,9 @@
<member name="P:Discord.WebSocket.SocketApplicationCommand.Description">
<inheritdoc/>
</member>
<member name="P:Discord.WebSocket.SocketApplicationCommand.DefaultPermission">
<inheritdoc/>
</member>
<member name="P:Discord.WebSocket.SocketApplicationCommand.Options">
<summary>
A collection of <see cref="T:Discord.WebSocket.SocketApplicationCommandOption"/>'s recieved over the gateway.
@@ -3256,6 +3280,9 @@
The <see cref="T:Discord.WebSocket.SocketGuild"/> where this application was created.
</summary>
</member>
<member name="M:Discord.WebSocket.SocketApplicationCommand.DeleteAsync(Discord.RequestOptions)">
<inheritdoc/>
</member>
<member name="T:Discord.WebSocket.SocketApplicationCommandChoice">
<summary>
Represents a choice for a <see cref="T:Discord.WebSocket.SocketApplicationCommandOption"/>.


+ 24
- 0
src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs View File

@@ -723,6 +723,30 @@ namespace Discord.WebSocket
public Task<RestGuildIntegration> CreateIntegrationAsync(ulong id, string type, RequestOptions options = null)
=> GuildHelper.CreateIntegrationAsync(this, Discord, id, type, options);

//Interactions
/// <summary>
/// Gets a collection of slash commands created by the current user in this guild.
/// </summary>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains a read-only collection of
/// slash commands created by the current user.
/// </returns>
public Task<IReadOnlyCollection<RestGuildCommand>> GetSlashCommandsAsync(RequestOptions options = null)
=> GuildHelper.GetSlashCommandsAsync(this, Discord, options);

/// <summary>
/// Gets a slash command in the current guild.
/// </summary>
/// <param name="id">The unique identifier of the slash command.</param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents the asynchronous get operation. The task result contains a
/// slash command created by the current user.
/// </returns>
public Task<RestGuildCommand> GetSlashCommandAsync(ulong id, RequestOptions options = null)
=> GuildHelper.GetSlashCommandAsync(this, id, Discord, options);

//Invites
/// <summary>
/// Gets a collection of all invites in this guild.


+ 10
- 1
src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketApplicationCommand.cs View File

@@ -1,3 +1,4 @@
using Discord.Rest;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
@@ -22,6 +23,9 @@ namespace Discord.WebSocket
/// <inheritdoc/>
public string Description { get; private set; }

/// <inheritdoc/>
public bool DefaultPermission { get; private set; }

/// <summary>
/// A collection of <see cref="SocketApplicationCommandOption"/>'s recieved over the gateway.
/// </summary>
@@ -56,13 +60,18 @@ namespace Discord.WebSocket
this.Description = model.Description;
this.Name = model.Name;
this.GuildId = model.GuildId;
this.DefaultPermission = model.DefaultPermission.GetValueOrDefault(true);


this.Options = model.Options.IsSpecified
? model.Options.Value.Select(x => SocketApplicationCommandOption.Create(x)).ToImmutableArray()
: new ImmutableArray<SocketApplicationCommandOption>();
}

public Task DeleteAsync(RequestOptions options = null) => throw new NotImplementedException();
/// <inheritdoc/>
public Task DeleteAsync(RequestOptions options = null)
=> InteractionHelper.DeleteGuildCommand(Discord, this.GuildId, this, options);

IReadOnlyCollection<IApplicationCommandOption> IApplicationCommand.Options => Options;
}
}

+ 14
- 3
src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketSlashCommandData.cs View File

@@ -54,9 +54,20 @@ namespace Discord.WebSocket
{
foreach (var channel in resolved.Channels.Value)
{
SocketChannel socketChannel = channel.Value.GuildId.IsSpecified
? SocketGuildChannel.Create(Discord.GetGuild(channel.Value.GuildId.Value), Discord.State, channel.Value)
: SocketDMChannel.Create(Discord, Discord.State, channel.Value);
SocketChannel socketChannel = guild != null
? guild.GetChannel(channel.Value.Id)
: Discord.GetChannel(channel.Value.Id);

if (socketChannel == null)
{
var channelModel = guild != null
? Discord.Rest.ApiClient.GetChannelAsync(guild.Id, channel.Value.Id).ConfigureAwait(false).GetAwaiter().GetResult()
: Discord.Rest.ApiClient.GetChannelAsync(channel.Value.Id).ConfigureAwait(false).GetAwaiter().GetResult();

socketChannel = guild != null
? SocketGuildChannel.Create(guild, Discord.State, channelModel)
: (SocketChannel)SocketChannel.CreatePrivate(Discord, Discord.State, channelModel);
}

Discord.State.AddChannel(socketChannel);
this.channels.Add(ulong.Parse(channel.Key), socketChannel);


+ 8
- 8
src/Discord.Net/Discord.Net.nuspec View File

@@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>Discord.Net.Labs</id>
<version>2.4.2$suffix$</version>
<version>2.4.3$suffix$</version>
<title>Discord.Net Labs</title>
<authors>Discord.Net Contributors</authors>
<owners>quinchs</owners>
@@ -15,22 +15,22 @@
<dependencies>
<group targetFramework="net461">
<dependency id="Discord.Net.Labs.Core" version="2.4.1$suffix$" />
<dependency id="Discord.Net.Labs.Rest" version="2.4.0$suffix$" />
<dependency id="Discord.Net.Labs.WebSocket" version="2.4.2$suffix$" />
<dependency id="Discord.Net.Labs.Rest" version="2.4.2$suffix$" />
<dependency id="Discord.Net.Labs.WebSocket" version="2.4.3$suffix$" />
<dependency id="Discord.Net.Labs.Commands" version="2.3.5$suffix$" />
<dependency id="Discord.Net.Labs.Webhook" version="2.3.4$suffix$" />
</group>
<group targetFramework="netstandard2.0">
<dependency id="Discord.Net.Labs.Core" version="2.4.1$suffix$" />
<dependency id="Discord.Net.Labs.Rest" version="2.4.0$suffix$" />
<dependency id="Discord.Net.Labs.WebSocket" version="2.4.2$suffix$" />
<dependency id="Discord.Net.Labs.Core" version="2.4.1$suffix$" />
<dependency id="Discord.Net.Labs.Rest" version="2.4.2$suffix$" />
<dependency id="Discord.Net.Labs.WebSocket" version="2.4.3$suffix$" />
<dependency id="Discord.Net.Labs.Commands" version="2.3.5$suffix$" />
<dependency id="Discord.Net.Labs.Webhook" version="2.3.4$suffix$" />
</group>
<group targetFramework="netstandard2.1">
<dependency id="Discord.Net.Labs.Core" version="2.4.1$suffix$" />
<dependency id="Discord.Net.Labs.Rest" version="2.4.0$suffix$" />
<dependency id="Discord.Net.Labs.WebSocket" version="2.4.2$suffix$" />
<dependency id="Discord.Net.Labs.Rest" version="2.4.2$suffix$" />
<dependency id="Discord.Net.Labs.WebSocket" version="2.4.3$suffix$" />
<dependency id="Discord.Net.Labs.Commands" version="2.3.5$suffix$" />
<dependency id="Discord.Net.Labs.Webhook" version="2.3.4$suffix$" />
</group>


Loading…
Cancel
Save