@@ -58,7 +58,7 @@ namespace Discord | |||
public bool? Required { get; set; } | |||
/// <summary> | |||
/// choices for string and int types for the user to pick from | |||
/// choices for string and int types for the user to pick from. | |||
/// </summary> | |||
public List<ApplicationCommandOptionChoiceProperties> Choices { get; set; } | |||
@@ -7,14 +7,14 @@ using System.Threading.Tasks; | |||
namespace Discord | |||
{ | |||
/// <summary> | |||
/// Represents a choice for a <see cref="IApplicationCommandInteractionDataOption"/>. This class is used when making new commands | |||
/// Represents a choice for a <see cref="IApplicationCommandInteractionDataOption"/>. This class is used when making new commands. | |||
/// </summary> | |||
public class ApplicationCommandOptionChoiceProperties | |||
{ | |||
private string _name; | |||
private object _value; | |||
/// <summary> | |||
/// The name of this choice | |||
/// The name of this choice. | |||
/// </summary> | |||
public string Name | |||
{ | |||
@@ -30,7 +30,7 @@ namespace Discord | |||
// Note: discord allows strings & ints as values. how should that be handled? | |||
// should we make this an object and then just type check it? | |||
/// <summary> | |||
/// The value of this choice | |||
/// The value of this choice. | |||
/// </summary> | |||
public object Value | |||
{ | |||
@@ -40,7 +40,7 @@ namespace Discord | |||
/// Deletes this command | |||
/// </summary> | |||
/// <param name="options">The options to be used when sending the request.</param> | |||
/// <returns></returns> | |||
/// <returns>A task that represents the asynchronous delete operation.</returns> | |||
Task DeleteAsync(RequestOptions options = null); | |||
} | |||
} |
@@ -7,22 +7,22 @@ using System.Threading.Tasks; | |||
namespace Discord | |||
{ | |||
/// <summary> | |||
/// Represents data of an Interaction Command, see <see href="https://discord.com/developers/docs/interactions/slash-commands#interaction-applicationcommandinteractiondata"/> | |||
/// Represents data of an Interaction Command, see <see href="https://discord.com/developers/docs/interactions/slash-commands#interaction-applicationcommandinteractiondata"/>. | |||
/// </summary> | |||
public interface IApplicationCommandInteractionData | |||
{ | |||
/// <summary> | |||
/// The snowflake id of this command | |||
/// The snowflake id of this command. | |||
/// </summary> | |||
ulong Id { get; } | |||
/// <summary> | |||
/// The name of this command | |||
/// The name of this command. | |||
/// </summary> | |||
string Name { get; } | |||
/// <summary> | |||
/// The params + values from the user | |||
/// The params + values from the user. | |||
/// </summary> | |||
IReadOnlyCollection<IApplicationCommandInteractionDataOption> Options { get; } | |||
} | |||
@@ -7,7 +7,7 @@ using System.Threading.Tasks; | |||
namespace Discord | |||
{ | |||
/// <summary> | |||
/// Represents a option group for a command, see <see href="https://discord.com/developers/docs/interactions/slash-commands#interaction-applicationcommandinteractiondataoption"/> | |||
/// Represents a option group for a command, see <see href="https://discord.com/developers/docs/interactions/slash-commands#interaction-applicationcommandinteractiondataoption"/>. | |||
/// </summary> | |||
public interface IApplicationCommandInteractionDataOption | |||
{ | |||
@@ -7,7 +7,7 @@ using System.Threading.Tasks; | |||
namespace Discord | |||
{ | |||
/// <summary> | |||
/// A class used to create slash commands | |||
/// A class used to create slash commands. | |||
/// </summary> | |||
public class SlashCommandCreationProperties | |||
{ | |||
@@ -9,20 +9,30 @@ using Model = Discord.API.ApplicationCommand; | |||
namespace Discord.Rest | |||
{ | |||
/// <summary> | |||
/// Represents a rest implementation of the <see cref="IApplicationCommand"/> | |||
/// Represents a Rest-based implementation of the <see cref="IApplicationCommand"/>. | |||
/// </summary> | |||
public abstract class RestApplicationCommand : RestEntity<ulong>, IApplicationCommand | |||
{ | |||
/// <inheritdoc/> | |||
public ulong ApplicationId { get; private set; } | |||
/// <inheritdoc/> | |||
public string Name { get; private set; } | |||
/// <inheritdoc/> | |||
public string Description { get; private set; } | |||
/// <summary> | |||
/// The options of this command. | |||
/// </summary> | |||
public IReadOnlyCollection<RestApplicationCommandOption> Options { get; private set; } | |||
/// <summary> | |||
/// The type of this rest application command. | |||
/// </summary> | |||
public RestApplicationCommandType CommandType { get; internal set; } | |||
/// <inheritdoc/> | |||
public DateTimeOffset CreatedAt | |||
=> SnowflakeUtils.FromSnowflake(this.Id); | |||
@@ -7,10 +7,15 @@ using Model = Discord.API.ApplicationCommandOptionChoice; | |||
namespace Discord.Rest | |||
{ | |||
/// <summary> | |||
/// Represents a Rest-based implementation of <see cref="IApplicationCommandOptionChoice"/>. | |||
/// </summary> | |||
public class RestApplicationCommandChoice : IApplicationCommandOptionChoice | |||
{ | |||
/// <inheritdoc/> | |||
public string Name { get; } | |||
/// <inheritdoc/> | |||
public object Value { get; } | |||
internal RestApplicationCommandChoice(Model model) | |||
@@ -8,20 +8,34 @@ using Model = Discord.API.ApplicationCommandOption; | |||
namespace Discord.Rest | |||
{ | |||
/// <summary> | |||
/// Represents a Rest-based implementation of <see cref="IApplicationCommandOption"/>. | |||
/// </summary> | |||
public class RestApplicationCommandOption : IApplicationCommandOption | |||
{ | |||
/// <inheritdoc/> | |||
public ApplicationCommandOptionType Type { get; private set; } | |||
/// <inheritdoc/> | |||
public string Name { get; private set; } | |||
/// <inheritdoc/> | |||
public string Description { get; private set; } | |||
/// <inheritdoc/> | |||
public bool? Default { get; private set; } | |||
/// <inheritdoc/> | |||
public bool? Required { get; private set; } | |||
/// <summary> | |||
/// A collection of <see cref="RestApplicationCommandChoice"/>'s for this command. | |||
/// </summary> | |||
public IReadOnlyCollection<RestApplicationCommandChoice> Choices { get; private set; } | |||
/// <summary> | |||
/// A collection of <see cref="RestApplicationCommandOption"/>'s for this command. | |||
/// </summary> | |||
public IReadOnlyCollection<RestApplicationCommandOption> Options { get; private set; } | |||
internal RestApplicationCommandOption() { } | |||
@@ -6,9 +6,19 @@ using System.Threading.Tasks; | |||
namespace Discord.Rest | |||
{ | |||
/// <summary> | |||
/// Represents a type of Rest-based command. | |||
/// </summary> | |||
public enum RestApplicationCommandType | |||
{ | |||
/// <summary> | |||
/// Specifies that this command is a Global command. | |||
/// </summary> | |||
GlobalCommand, | |||
/// <summary> | |||
/// Specifies that this command is a Guild specific command. | |||
/// </summary> | |||
GuildCommand | |||
} | |||
} |
@@ -8,7 +8,7 @@ using Model = Discord.API.ApplicationCommand; | |||
namespace Discord.Rest | |||
{ | |||
/// <summary> | |||
/// Represents a global Slash command | |||
/// Represents a global Slash command. | |||
/// </summary> | |||
public class RestGlobalCommand : RestApplicationCommand | |||
{ | |||
@@ -24,6 +24,8 @@ namespace Discord.Rest | |||
entity.Update(model); | |||
return entity; | |||
} | |||
/// <inheritdoc/> | |||
public override async Task DeleteAsync(RequestOptions options = null) | |||
=> await InteractionHelper.DeleteGlobalCommand(Discord, this).ConfigureAwait(false); | |||
@@ -33,7 +35,7 @@ namespace Discord.Rest | |||
/// <param name="func">The delegate containing the properties to modify the command with.</param> | |||
/// <param name="options">The options to be used when sending the request.</param> | |||
/// <returns> | |||
/// The modified command | |||
/// The modified command. | |||
/// </returns> | |||
public async Task<RestGlobalCommand> ModifyAsync(Action<ApplicationCommandProperties> func, RequestOptions options = null) | |||
=> await InteractionHelper.ModifyGlobalCommand(Discord, this, func, options).ConfigureAwait(false); | |||
@@ -7,9 +7,16 @@ using Model = Discord.API.ApplicationCommand; | |||
namespace Discord.Rest | |||
{ | |||
/// <summary> | |||
/// Represents a Rest-based guild command. | |||
/// </summary> | |||
public class RestGuildCommand : RestApplicationCommand | |||
{ | |||
/// <summary> | |||
/// The guild Id where this command originates. | |||
/// </summary> | |||
public ulong GuildId { get; set; } | |||
internal RestGuildCommand(BaseDiscordClient client, ulong id, ulong guildId) | |||
: base(client, id) | |||
{ | |||
@@ -24,6 +31,7 @@ namespace Discord.Rest | |||
return entity; | |||
} | |||
/// <inheritdoc/> | |||
public override async Task DeleteAsync(RequestOptions options = null) | |||
=> await InteractionHelper.DeleteGuildCommand(Discord, this).ConfigureAwait(false); | |||
@@ -8,19 +8,31 @@ using Model = Discord.API.Gateway.ApplicationCommandCreatedUpdatedEvent; | |||
namespace Discord.WebSocket | |||
{ | |||
/// <summary> | |||
/// Represends a Websocket-based <see cref="IApplicationCommand"/> recieved over the gateway. | |||
/// </summary> | |||
public class SocketApplicationCommand : SocketEntity<ulong>, IApplicationCommand | |||
{ | |||
/// <inheritdoc/> | |||
public ulong ApplicationId { get; private set; } | |||
/// <inheritdoc/> | |||
public string Name { get; private set; } | |||
/// <inheritdoc/> | |||
public string Description { get; private set; } | |||
/// <summary> | |||
/// A collection of <see cref="SocketApplicationCommandOption"/>'s recieved over the gateway. | |||
/// </summary> | |||
public IReadOnlyCollection<SocketApplicationCommandOption> Options { get; private set; } | |||
public DateTimeOffset CreatedAt | |||
=> SnowflakeUtils.FromSnowflake(this.Id); | |||
/// <summary> | |||
/// The <see cref="SocketGuild"/> where this application was created. | |||
/// </summary> | |||
public SocketGuild Guild | |||
=> Discord.GetGuild(this.GuildId); | |||
private ulong GuildId { get; set; } | |||
@@ -8,12 +8,14 @@ using Model = Discord.API.ApplicationCommandOptionChoice; | |||
namespace Discord.WebSocket | |||
{ | |||
/// <summary> | |||
/// Represents a choice for a <see cref="SocketApplicationCommandOption"/> | |||
/// Represents a choice for a <see cref="SocketApplicationCommandOption"/>. | |||
/// </summary> | |||
public class SocketApplicationCommandChoice : IApplicationCommandOptionChoice | |||
{ | |||
/// <inheritdoc/> | |||
public string Name { get; private set; } | |||
/// <inheritdoc/> | |||
public object Value { get; private set; } | |||
internal SocketApplicationCommandChoice() { } | |||
@@ -9,18 +9,23 @@ using Model = Discord.API.ApplicationCommandOption; | |||
namespace Discord.WebSocket | |||
{ | |||
/// <summary> | |||
/// Represents an option for a <see cref="SocketApplicationCommand"/> | |||
/// Represents an option for a <see cref="SocketApplicationCommand"/>. | |||
/// </summary> | |||
public class SocketApplicationCommandOption : IApplicationCommandOption | |||
{ | |||
/// <inheritdoc/> | |||
public string Name { get; private set; } | |||
/// <inheritdoc/> | |||
public ApplicationCommandOptionType Type { get; private set; } | |||
/// <inheritdoc/> | |||
public string Description { get; private set; } | |||
/// <inheritdoc/> | |||
public bool? Default { get; private set; } | |||
/// <inheritdoc/> | |||
public bool? Required { get; private set; } | |||
/// <summary> | |||
@@ -9,52 +9,52 @@ using Model = Discord.API.Gateway.InteractionCreated; | |||
namespace Discord.WebSocket | |||
{ | |||
/// <summary> | |||
/// Represents an Interaction recieved over the gateway | |||
/// Represents an Interaction recieved over the gateway. | |||
/// </summary> | |||
public class SocketInteraction : SocketEntity<ulong>, IDiscordInteraction | |||
{ | |||
/// <summary> | |||
/// The <see cref="SocketGuild"/> this interaction was used in | |||
/// The <see cref="SocketGuild"/> this interaction was used in. | |||
/// </summary> | |||
public SocketGuild Guild | |||
=> Discord.GetGuild(GuildId); | |||
/// <summary> | |||
/// The <see cref="SocketTextChannel"/> this interaction was used in | |||
/// The <see cref="SocketTextChannel"/> this interaction was used in. | |||
/// </summary> | |||
public SocketTextChannel Channel | |||
=> Guild.GetTextChannel(ChannelId); | |||
/// <summary> | |||
/// The <see cref="SocketGuildUser"/> who triggered this interaction | |||
/// The <see cref="SocketGuildUser"/> who triggered this interaction. | |||
/// </summary> | |||
public SocketGuildUser Member | |||
=> Guild.GetUser(MemberId); | |||
/// <summary> | |||
/// The type of this interaction | |||
/// The type of this interaction. | |||
/// </summary> | |||
public InteractionType Type { get; private set; } | |||
/// <summary> | |||
/// The data associated with this interaction | |||
/// The data associated with this interaction. | |||
/// </summary> | |||
public SocketInteractionData Data { get; private set; } | |||
/// <summary> | |||
/// The token used to respond to this interaction | |||
/// The token used to respond to this interaction. | |||
/// </summary> | |||
public string Token { get; private set; } | |||
/// <summary> | |||
/// The version of this interaction | |||
/// The version of this interaction. | |||
/// </summary> | |||
public int Version { get; private set; } | |||
public DateTimeOffset CreatedAt { get; } | |||
/// <summary> | |||
/// <see langword="true"/> if the token is valid for replying to, otherwise <see langword="false"/> | |||
/// <see langword="true"/> if the token is valid for replying to, otherwise <see langword="false"/>. | |||
/// </summary> | |||
public bool IsValidToken | |||
=> CheckToken(); | |||
@@ -78,7 +78,7 @@ namespace Discord.WebSocket | |||
internal void Update(Model model) | |||
{ | |||
this.Data = model.Data.IsSpecified | |||
? SocketInteractionData.Create(this.Discord, model.Data.Value) | |||
? SocketInteractionData.Create(this.Discord, model.Data.Value, model.GuildId) | |||
: null; | |||
this.GuildId = model.GuildId; | |||
@@ -101,17 +101,17 @@ namespace Discord.WebSocket | |||
/// <see cref="FollowupAsync(string, bool, Embed, InteractionResponseType, AllowedMentions, RequestOptions)"/> instead. | |||
/// </para> | |||
/// </summary> | |||
/// <param name="text">The text of the message to be sent</param> | |||
/// <param name="isTTS"><see langword="true"/> if the message should be read out by a text-to-speech reader, otherwise <see langword="false"/></param> | |||
/// <param name="embed">A <see cref="Embed"/> to send with this response</param> | |||
/// <param name="Type">The type of response to this Interaction</param> | |||
/// <param name="allowedMentions">The allowed mentions for this response</param> | |||
/// <param name="options">The request options for this response</param> | |||
/// <param name="text">The text of the message to be sent.</param> | |||
/// <param name="isTTS"><see langword="true"/> if the message should be read out by a text-to-speech reader, otherwise <see langword="false"/>.</param> | |||
/// <param name="embed">A <see cref="Embed"/> to send with this response.</param> | |||
/// <param name="Type">The type of response to this Interaction.</param> | |||
/// <param name="allowedMentions">The allowed mentions for this response.</param> | |||
/// <param name="options">The request options for this response.</param> | |||
/// <returns> | |||
/// The <see cref="IMessage"/> sent as the response. If this is the first acknowledgement, it will return null; | |||
/// The <see cref="IMessage"/> sent as the response. If this is the first acknowledgement, it will return null. | |||
/// </returns> | |||
/// <exception cref="ArgumentOutOfRangeException">Message content is too long, length must be less or equal to <see cref="DiscordConfig.MaxMessageSize"/>.</exception> | |||
/// <exception cref="InvalidOperationException">The parameters provided were invalid or the token was invalid</exception> | |||
/// <exception cref="InvalidOperationException">The parameters provided were invalid or the token was invalid.</exception> | |||
public async Task<IMessage> RespondAsync(string text = null, bool isTTS = false, Embed embed = null, InteractionResponseType Type = InteractionResponseType.ChannelMessageWithSource, AllowedMentions allowedMentions = null, RequestOptions options = null) | |||
{ | |||
@@ -162,16 +162,16 @@ namespace Discord.WebSocket | |||
} | |||
/// <summary> | |||
/// Sends a followup message for this interaction | |||
/// Sends a followup message for this interaction. | |||
/// </summary> | |||
/// <param name="text">The text of the message to be sent</param> | |||
/// <param name="isTTS"><see langword="true"/> if the message should be read out by a text-to-speech reader, otherwise <see langword="false"/></param> | |||
/// <param name="embed">A <see cref="Embed"/> to send with this response</param> | |||
/// <param name="Type">The type of response to this Interaction</param> | |||
/// <param name="allowedMentions">The allowed mentions for this response</param> | |||
/// <param name="options">The request options for this response</param> | |||
/// <param name="isTTS"><see langword="true"/> if the message should be read out by a text-to-speech reader, otherwise <see langword="false"/>.</param> | |||
/// <param name="embed">A <see cref="Embed"/> to send with this response.</param> | |||
/// <param name="Type">The type of response to this Interaction.</param> | |||
/// <param name="allowedMentions">The allowed mentions for this response.</param> | |||
/// <param name="options">The request options for this response.</param> | |||
/// <returns> | |||
/// The sent message | |||
/// The sent message. | |||
/// </returns> | |||
public async Task<IMessage> FollowupAsync(string text = null, bool isTTS = false, Embed embed = null, InteractionResponseType Type = InteractionResponseType.ChannelMessageWithSource, | |||
AllowedMentions allowedMentions = null, RequestOptions options = null) | |||
@@ -195,10 +195,10 @@ namespace Discord.WebSocket | |||
} | |||
/// <summary> | |||
/// Acknowledges this interaction with the <see cref="InteractionResponseType.ACKWithSource"/> | |||
/// Acknowledges this interaction with the <see cref="InteractionResponseType.ACKWithSource"/>. | |||
/// </summary> | |||
/// <returns> | |||
/// A task that represents the asynchronous operation of acknowledging the interaction | |||
/// A task that represents the asynchronous operation of acknowledging the interaction. | |||
/// </returns> | |||
public async Task AcknowledgeAsync(RequestOptions options = null) | |||
{ | |||
@@ -10,28 +10,36 @@ namespace Discord.WebSocket | |||
{ | |||
public class SocketInteractionData : SocketEntity<ulong>, IApplicationCommandInteractionData | |||
{ | |||
/// <inheritdoc/> | |||
public string Name { get; private set; } | |||
/// <summary> | |||
/// The <see cref="SocketInteractionDataOption"/>'s recieved with this interaction. | |||
/// </summary> | |||
public IReadOnlyCollection<SocketInteractionDataOption> Options { get; private set; } | |||
private ulong guildId; | |||
internal SocketInteractionData(DiscordSocketClient client, ulong id) | |||
: base(client, id) | |||
{ | |||
} | |||
internal static SocketInteractionData Create(DiscordSocketClient client, Model model) | |||
internal static SocketInteractionData Create(DiscordSocketClient client, Model model, ulong guildId) | |||
{ | |||
var entity = new SocketInteractionData(client, model.Id); | |||
entity.Update(model); | |||
entity.Update(model, guildId); | |||
return entity; | |||
} | |||
internal void Update(Model model) | |||
internal void Update(Model model, ulong guildId) | |||
{ | |||
this.Name = model.Name; | |||
this.guildId = guildId; | |||
this.Options = model.Options.IsSpecified | |||
? model.Options.Value.Select(x => new SocketInteractionDataOption(x)).ToImmutableArray() | |||
? model.Options.Value.Select(x => new SocketInteractionDataOption(x, this.Discord, guildId)).ToImmutableArray() | |||
: null; | |||
} | |||
IReadOnlyCollection<IApplicationCommandInteractionDataOption> IApplicationCommandInteractionData.Options => Options; | |||
@@ -8,21 +8,91 @@ using Model = Discord.API.ApplicationCommandInteractionDataOption; | |||
namespace Discord.WebSocket | |||
{ | |||
/// <summary> | |||
/// Represents a Websocket-based <see cref="IApplicationCommandInteractionDataOption"/> recieved by the gateway | |||
/// </summary> | |||
public class SocketInteractionDataOption : IApplicationCommandInteractionDataOption | |||
{ | |||
/// <inheritdoc/> | |||
public string Name { get; private set; } | |||
public object? Value { get; private set; } | |||
public IReadOnlyCollection<IApplicationCommandInteractionDataOption> Options { get; private set; } | |||
/// <inheritdoc/> | |||
public object Value { get; private set; } | |||
internal SocketInteractionDataOption(Model model) | |||
/// <summary> | |||
/// The sub command options recieved for this sub command group. | |||
/// </summary> | |||
public IReadOnlyCollection<SocketInteractionDataOption> Options { get; private set; } | |||
private DiscordSocketClient discord; | |||
private ulong guild; | |||
internal SocketInteractionDataOption() { } | |||
internal SocketInteractionDataOption(Model model, DiscordSocketClient discord, ulong guild) | |||
{ | |||
this.Name = Name; | |||
this.Value = model.Value.IsSpecified ? model.Value.Value : null; | |||
this.discord = discord; | |||
this.guild = guild; | |||
this.Options = model.Options.IsSpecified | |||
? model.Options.Value.Select(x => new SocketInteractionDataOption(x)).ToImmutableArray() | |||
? model.Options.Value.Select(x => new SocketInteractionDataOption(x, discord, guild)).ToImmutableArray() | |||
: null; | |||
} | |||
// Converters | |||
public static explicit operator bool(SocketInteractionDataOption option) | |||
=> (bool)option.Value; | |||
public static explicit operator int(SocketInteractionDataOption option) | |||
=> (int)option.Value; | |||
public static explicit operator string(SocketInteractionDataOption option) | |||
=> option.Value.ToString(); | |||
public static explicit operator SocketGuildChannel(SocketInteractionDataOption option) | |||
{ | |||
if (option.Value is ulong id) | |||
{ | |||
var guild = option.discord.GetGuild(option.guild); | |||
if (guild == null) | |||
return null; | |||
return guild.GetChannel(id); | |||
} | |||
return null; | |||
} | |||
public static explicit operator SocketRole(SocketInteractionDataOption option) | |||
{ | |||
if (option.Value is ulong id) | |||
{ | |||
var guild = option.discord.GetGuild(option.guild); | |||
if (guild == null) | |||
return null; | |||
return guild.GetRole(id); | |||
} | |||
return null; | |||
} | |||
public static explicit operator SocketGuildUser(SocketInteractionDataOption option) | |||
{ | |||
if(option.Value is ulong id) | |||
{ | |||
var guild = option.discord.GetGuild(option.guild); | |||
if (guild == null) | |||
return null; | |||
return guild.GetUser(id); | |||
} | |||
return null; | |||
} | |||
IReadOnlyCollection<IApplicationCommandInteractionDataOption> IApplicationCommandInteractionDataOption.Options => this.Options; | |||
} | |||
} |