| @@ -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; | |||
| } | |||
| } | |||