Browse Source

Merge w/ Parent Interactions branch

pull/1923/head
Matt Smith 4 years ago
parent
commit
f64db8b745
30 changed files with 476 additions and 106 deletions
  1. +1
    -1
      src/Discord.Net.Core/Discord.Net.Core.csproj
  2. +9
    -4
      src/Discord.Net.Core/Entities/Interactions/Message Components/ActionRowComponent.cs
  3. +27
    -7
      src/Discord.Net.Core/Entities/Interactions/Message Components/ButtonComponent.cs
  4. +176
    -8
      src/Discord.Net.Core/Entities/Interactions/Message Components/ComponentBuilder.cs
  5. +10
    -4
      src/Discord.Net.Core/Entities/Interactions/Message Components/MessageComponent.cs
  6. +5
    -0
      src/Discord.Net.Core/Entities/Messages/MessageProperties.cs
  7. +25
    -0
      src/Discord.Net.Rest/API/Common/ActionRowComponent.cs
  8. +66
    -0
      src/Discord.Net.Rest/API/Common/ButtonComponent.cs
  9. +1
    -1
      src/Discord.Net.Rest/API/Common/InteractionApplicationCommandCallbackData.cs
  10. +1
    -1
      src/Discord.Net.Rest/API/Common/Message.cs
  11. +1
    -1
      src/Discord.Net.Rest/API/Rest/CreateMessageParams.cs
  12. +1
    -1
      src/Discord.Net.Rest/API/Rest/CreateWebhookMessageParams.cs
  13. +3
    -1
      src/Discord.Net.Rest/API/Rest/ModifyMessageParams.cs
  14. +1
    -1
      src/Discord.Net.Rest/API/Rest/UploadFileParams.cs
  15. +3
    -1
      src/Discord.Net.Rest/Discord.Net.Rest.csproj
  16. +1
    -1
      src/Discord.Net.Rest/DiscordRestApiClient.cs
  17. +2
    -2
      src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs
  18. +2
    -1
      src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs
  19. +10
    -3
      src/Discord.Net.Rest/Entities/Messages/RestMessage.cs
  20. +13
    -3
      src/Discord.Net.WebSocket/API/Gateway/InteractionCreated.cs
  21. +1
    -1
      src/Discord.Net.WebSocket/Discord.Net.WebSocket.csproj
  22. +19
    -12
      src/Discord.Net.WebSocket/DiscordSocketClient.cs
  23. +32
    -3
      src/Discord.Net.WebSocket/Entities/Interaction/Message Components/SocketMessageComponent.cs
  24. +3
    -0
      src/Discord.Net.WebSocket/Entities/Interaction/Message Components/SocketMessageComponentData.cs
  25. +4
    -4
      src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketSlashCommand.cs
  26. +4
    -7
      src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketSlashCommandData.cs
  27. +5
    -7
      src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketSlashCommandDataOption.cs
  28. +30
    -18
      src/Discord.Net.WebSocket/Entities/Interaction/SocketInteraction.cs
  29. +10
    -3
      src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs
  30. +10
    -10
      src/Discord.Net/Discord.Net.nuspec

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

@@ -8,7 +8,7 @@
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">net461;netstandard2.0;netstandard2.1</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">netstandard2.0;netstandard2.1</TargetFrameworks>
<PackageId>Discord.Net.Labs.Core</PackageId>
<Version>2.3.3</Version>
<Version>2.3.4</Version>
<Product>Discord.Net.Labs.Core</Product>
<RepositoryUrl>https://github.com/Discord-Net-Labs/Discord.Net-Labs</RepositoryUrl>
<PackageIcon>Temporary.png</PackageIcon>


+ 9
- 4
src/Discord.Net.Core/Entities/Interactions/Message Components/ActionRowComponent.cs View File

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

namespace Discord
{
/// <summary>
/// Represents a <see cref="IMessageComponent"/> Row for child components to live in.
/// </summary>
public class ActionRowComponent : IMessageComponent
{
[JsonProperty("type")]
/// <inheritdoc/>
public ComponentType Type { get; } = ComponentType.ActionRow;

[JsonProperty("components")]
public IReadOnlyCollection<IMessageComponent> Components { get; internal set; }
/// <summary>
/// The child components in this row.
/// </summary>
public IReadOnlyCollection<ButtonComponent> Components { get; internal set; }

internal ActionRowComponent() { }
internal ActionRowComponent(IReadOnlyCollection<IMessageComponent> components)
internal ActionRowComponent(List<ButtonComponent> components)
{
this.Components = components;
}


+ 27
- 7
src/Discord.Net.Core/Entities/Interactions/Message Components/ButtonComponent.cs View File

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

namespace Discord
{
/// <summary>
/// Represents a <see cref="IMessageComponent"/> Button.
/// </summary>
public class ButtonComponent : IMessageComponent
{
[JsonProperty("type")]
/// <inheritdoc/>
public ComponentType Type { get; } = ComponentType.Button;

[JsonProperty("style")]
/// <summary>
/// The <see cref="ButtonStyle"/> of this button, example buttons with each style can be found <see href="https://discord.com/assets/7bb017ce52cfd6575e21c058feb3883b.png">Here</see>.
/// </summary>
public ButtonStyle Style { get; }

[JsonProperty("label")]
/// <summary>
/// The label of the button, this is the text that is shown.
/// </summary>
public string Label { get; }

[JsonProperty("emoji")]
/// <summary>
/// A <see cref="IEmote"/> that will be displayed with this button.
/// </summary>
public IEmote Emote { get; }

[JsonProperty("custom_id")]
/// <summary>
/// A unique id that will be sent with a <see cref="IDiscordInteraction"/>. This is how you know what button was pressed.
/// </summary>
public string CustomId { get; }

[JsonProperty("url")]
/// <summary>
/// A URL for a <see cref="ButtonStyle.Link"/> button.
/// </summary>
/// <remarks>
/// You cannot have a button with a <b>URL</b> and a <b>CustomId</b>.
/// </remarks>
public string Url { get; }

[JsonProperty("disabled")]
/// <summary>
/// Whether this button is disabled or not.
/// </summary>
public bool Disabled { get; }

internal ButtonComponent(ButtonStyle style, string label, IEmote emote, string customId, string url, bool disabled)
@@ -39,5 +57,7 @@ namespace Discord
this.Url = url;
this.Disabled = disabled;
}


}
}

+ 176
- 8
src/Discord.Net.Core/Entities/Interactions/Message Components/ComponentBuilder.cs View File

@@ -6,10 +6,19 @@ using System.Threading.Tasks;

namespace Discord
{
/// <summary>
/// Represents a builder for creating a <see cref="MessageComponent"/>.
/// </summary>
public class ComponentBuilder
{
/// <summary>
/// The max amount of rows a message can have.
/// </summary>
public const int MaxActionRowCount = 5;

/// <summary>
/// Gets or sets the Action Rows for this Component Builder.
/// </summary>
public List<ActionRowBuilder> ActionRows
{
get => _actionRows;
@@ -25,11 +34,22 @@ namespace Discord

private List<ActionRowBuilder> _actionRows { get; set; }

/// <summary>
/// Adds a button to the specified row.
/// </summary>
/// <param name="label">The label text for the newly added button.</param>
/// <param name="style">The style of this newly added button.</param>
/// <param name="emote">A <see cref="IEmote"/> to be used with this button.</param>
/// <param name="customId">The custom id of the newly added button.</param>
/// <param name="url">A URL to be used only if the <see cref="ButtonStyle"/> is a Link.</param>
/// <param name="disabled">Whether or not the newly created button is disabled.</param>
/// <param name="row">The row the button should be placed on.</param>
/// <returns>The current builder.</returns>
public ComponentBuilder WithButton(
string label,
string customId,
ButtonStyle style = ButtonStyle.Primary,
IEmote emote = null,
string customId = null,
string url = null,
bool disabled = false,
int row = 0)
@@ -45,9 +65,20 @@ namespace Discord
return this.WithButton(button, row);
}

/// <summary>
/// Adds a button to the first row.
/// </summary>
/// <param name="button">The button to add to the first row.</param>
/// <returns>The current builder.</returns>
public ComponentBuilder WithButton(ButtonBuilder button)
=> this.WithButton(button, 0);

/// <summary>
/// Adds a button to the specified row.
/// </summary>
/// <param name="button">The button to add.</param>
/// <param name="row">The row to add the button.</param>
/// <returns>The current builder.</returns>
public ComponentBuilder WithButton(ButtonBuilder button, int row)
{
var builtButton = button.Build();
@@ -75,6 +106,10 @@ namespace Discord
return this;
}

/// <summary>
/// Builds this builder into a <see cref="MessageComponent"/> used to send your components.
/// </summary>
/// <returns>A <see cref="MessageComponent"/> that can be sent with <see cref="IMessageChannel.SendMessageAsync(string, bool, Embed, RequestOptions, AllowedMentions, MessageReference, MessageComponent)"/></returns>
public MessageComponent Build()
{
if (this._actionRows != null)
@@ -84,10 +119,20 @@ namespace Discord
}
}

/// <summary>
/// Represents a class used to build Action rows.
/// </summary>
public class ActionRowBuilder
{
/// <summary>
/// The max amount of child components this row can hold.
/// </summary>
public const int MaxChildCount = 5;
public List<IMessageComponent> Components

/// <summary>
/// Gets or sets the components inside this row.
/// </summary>
public List<ButtonComponent> Components
{
get => _components;
set
@@ -99,33 +144,70 @@ namespace Discord
}
}

private List<IMessageComponent> _components { get; set; }
private List<ButtonComponent> _components { get; set; }

public ActionRowBuilder WithComponents(List<IMessageComponent> components)
/// <summary>
/// Adds a list of components to the current row.
/// </summary>
/// <param name="components">The list of components to add.</param>
/// <returns>The current builder.</returns>
public ActionRowBuilder WithComponents(List<ButtonComponent> components)
{
this.Components = components;
return this;
}

public ActionRowBuilder WithComponent(IMessageComponent component)
/// <summary>
/// Adds a component at the end of the current row.
/// </summary>
/// <param name="component">The component to add.</param>
/// <returns>The current builder.</returns>
public ActionRowBuilder WithComponent(ButtonComponent component)
{
if (this.Components == null)
this.Components = new List<IMessageComponent>();
this.Components = new List<ButtonComponent>();

this.Components.Add(component);

return this;
}

/// <summary>
/// Builds the current builder to a <see cref="ActionRowComponent"/> that can be used within a <see cref="ComponentBuilder"/>
/// </summary>
/// <returns>A <see cref="ActionRowComponent"/> that can be used within a <see cref="ComponentBuilder"/></returns>
/// <exception cref="ArgumentNullException"><see cref="Components"/> cannot be null.</exception>
/// <exception cref="ArgumentException">There must be at least 1 component in a row.</exception>
public ActionRowComponent Build()
=> new ActionRowComponent(this._components);
{
if (this.Components == null)
throw new ArgumentNullException($"{nameof(Components)} cannot be null!");

if (this.Components.Count == 0)
throw new ArgumentException("There must be at least 1 component in a row");

return new ActionRowComponent(this._components);
}
}

/// <summary>
/// Represents a class used to build <see cref="ButtonComponent"/>'s.
/// </summary>
public class ButtonBuilder
{
/// <summary>
/// The max length of a <see cref="ButtonComponent.Label"/>.
/// </summary>
public const int MaxLabelLength = 80;

/// <summary>
/// The max length of a <see cref="ButtonComponent.CustomId"/>.
/// </summary>
public const int MaxCustomIdLength = 100;

/// <summary>
/// Gets or sets the label of the current button.
/// </summary>
public string Label
{
get => _label;
@@ -139,6 +221,9 @@ namespace Discord
}
}

/// <summary>
/// Gets or sets the custom id of the current button.
/// </summary>
public string CustomId
{
get => _customId;
@@ -151,15 +236,36 @@ namespace Discord
}
}

/// <summary>
/// Gets or sets the <see cref="ButtonStyle"/> of the current button.
/// </summary>
public ButtonStyle Style { get; set; }

/// <summary>
/// Gets or sets the <see cref="IEmote"/> of the current button.
/// </summary>
public IEmote Emote { get; set; }

/// <summary>
/// Gets or sets the url of the current button.
/// </summary>
public string Url { get; set; }

/// <summary>
/// Gets or sets whether the current button is disabled.
/// </summary>
public bool Disabled { get; set; }


private string _label;
private string _customId;

/// <summary>
/// Creates a button with the <see cref="ButtonStyle.Link"/> style.
/// </summary>
/// <param name="label">The label to use on the newly created link button.</param>
/// <param name="url">The url for this link button to go to.</param>
/// <returns>A builder with the newly created button.</returns>
public static ButtonBuilder CreateLinkButton(string label, string url)
{
var builder = new ButtonBuilder()
@@ -170,6 +276,12 @@ namespace Discord
return builder;
}

/// <summary>
/// Creates a button with the <see cref="ButtonStyle.Danger"/> style.
/// </summary>
/// <param name="label">The label for this danger button.</param>
/// <param name="customId">The custom id for this danger button.</param>
/// <returns>A builder with the newly created button.</returns>
public static ButtonBuilder CreateDangerButton(string label, string customId)
{
var builder = new ButtonBuilder()
@@ -180,6 +292,12 @@ namespace Discord
return builder;
}

/// <summary>
/// Creates a button with the <see cref="ButtonStyle.Primary"/> style.
/// </summary>
/// <param name="label">The label for this primary button.</param>
/// <param name="customId">The custom id for this primary button.</param>
/// <returns>A builder with the newly created button.</returns>
public static ButtonBuilder CreatePrimaryButton(string label, string customId)
{
var builder = new ButtonBuilder()
@@ -190,6 +308,12 @@ namespace Discord
return builder;
}

/// <summary>
/// Creates a button with the <see cref="ButtonStyle.Secondary"/> style.
/// </summary>
/// <param name="label">The label for this secondary button.</param>
/// <param name="customId">The custom id for this secondary button.</param>
/// <returns>A builder with the newly created button.</returns>
public static ButtonBuilder CreateSecondaryButton(string label, string customId)
{
var builder = new ButtonBuilder()
@@ -200,6 +324,12 @@ namespace Discord
return builder;
}

/// <summary>
/// Creates a button with the <see cref="ButtonStyle.Success"/> style.
/// </summary>
/// <param name="label">The label for this success button.</param>
/// <param name="customId">The custom id for this success button.</param>
/// <returns>A builder with the newly created button.</returns>
public static ButtonBuilder CreateSuccessButton(string label, string customId)
{
var builder = new ButtonBuilder()
@@ -210,41 +340,78 @@ namespace Discord
return builder;
}

/// <summary>
/// Sets the current buttons label to the specified text.
/// </summary>
/// <param name="label">The text for the label</param>
/// <returns>The current builder.</returns>
public ButtonBuilder WithLabel(string label)
{
this.Label = label;
return this;
}

/// <summary>
/// Sets the current buttons style.
/// </summary>
/// <param name="style">The style for this builders button.</param>
/// <returns>The current builder.</returns>
public ButtonBuilder WithStyle(ButtonStyle style)
{
this.Style = style;
return this;
}

/// <summary>
/// Sets the current buttons emote.
/// </summary>
/// <param name="emote">The emote to use for the current button.</param>
/// <returns>The current builder.</returns>
public ButtonBuilder WithEmote(IEmote emote)
{
this.Emote = emote;
return this;
}

/// <summary>
/// Sets the current buttons url.
/// </summary>
/// <param name="url">The url to use for the current button.</param>
/// <returns>The current builder.</returns>
public ButtonBuilder WithUrl(string url)
{
this.Url = url;
return this;
}

/// <summary>
/// Sets the custom id of the current button.
/// </summary>
/// <param name="id">The id to use for the current button.</param>
/// <returns>The current builder.</returns>
public ButtonBuilder WithCustomId(string id)
{
this.CustomId = id;
return this;
}

/// <summary>
/// Sets whether the current button is disabled.
/// </summary>
/// <param name="disabled">Whether the current button is disabled or not.</param>
/// <returns>The current builder.</returns>
public ButtonBuilder WithDisabled(bool disabled)
{
this.Disabled = disabled;
return this;
}

/// <summary>
/// Builds this builder into a <see cref="ButtonComponent"/> to be used in a <see cref="ComponentBuilder"/>.
/// </summary>
/// <returns>A <see cref="ButtonComponent"/> to be used in a <see cref="ComponentBuilder"/>.</returns>
/// <exception cref="InvalidOperationException">A button cannot contain a URL and a CustomId.</exception>
/// <exception cref="ArgumentException">A button must have an Emote or a label.</exception>
public ButtonComponent Build()
{
if (string.IsNullOrEmpty(this.Label) && this.Emote == null)
@@ -255,7 +422,8 @@ namespace Discord

if (this.Style == ButtonStyle.Link && !string.IsNullOrEmpty(this.CustomId))
this.CustomId = null;
else if (!string.IsNullOrEmpty(this.Url))

else if (this.Style != ButtonStyle.Link && !string.IsNullOrEmpty(this.Url)) // Thanks 𝑴𝒓𝑪𝒂𝒌𝒆𝑺𝒍𝒂𝒚𝒆𝒓 :D
this.Url = null;

return new ButtonComponent(this.Style, this.Label, this.Emote, this.CustomId, this.Url, this.Disabled);


+ 10
- 4
src/Discord.Net.Core/Entities/Interactions/Message Components/MessageComponent.cs View File

@@ -6,19 +6,25 @@ using System.Threading.Tasks;

namespace Discord
{
/// <summary>
/// Represents a component object used to send components with messages.
/// </summary>
public class MessageComponent
{
public IReadOnlyCollection<IMessageComponent> Components { get; }
/// <summary>
/// The components to be used in a message.
/// </summary>
public IReadOnlyCollection<ActionRowComponent> Components { get; }

internal MessageComponent(List<ActionRowComponent> components)
{
this.Components = components;
}

/// <summary>
/// Returns a empty <see cref="MessageComponent"/>.
/// </summary>
internal static MessageComponent Empty
=> new MessageComponent(new List<ActionRowComponent>());

internal IMessageComponent[] ToModel()
=> this.Components.ToArray();
}
}

+ 5
- 0
src/Discord.Net.Core/Entities/Messages/MessageProperties.cs View File

@@ -21,5 +21,10 @@ namespace Discord
/// Gets or sets the embed the message should display.
/// </summary>
public Optional<Embed> Embed { get; set; }

/// <summary>
/// Gets or sets the components for this message.
/// </summary>
public Optional<MessageComponent> Components { get; set; }
}
}

+ 25
- 0
src/Discord.Net.Rest/API/Common/ActionRowComponent.cs View File

@@ -0,0 +1,25 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord.API
{
internal class ActionRowComponent
{
[JsonProperty("type")]
public ComponentType Type { get; set; }

[JsonProperty("components")]
public List<ButtonComponent> Components { get; set; }

internal ActionRowComponent() { }
internal ActionRowComponent(Discord.ActionRowComponent c)
{
this.Type = c.Type;
this.Components = c.Components?.Select(x => new ButtonComponent(x)).ToList();
}
}
}

+ 66
- 0
src/Discord.Net.Rest/API/Common/ButtonComponent.cs View File

@@ -0,0 +1,66 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord.API
{
internal class ButtonComponent
{
[JsonProperty("type")]
public ComponentType Type { get; set; }

[JsonProperty("style")]
public ButtonStyle Style { get; set; }

[JsonProperty("label")]
public Optional<string> Label { get; set; }

[JsonProperty("emoji")]
public Optional<Emoji> Emote { get; set; }

[JsonProperty("custom_id")]
public Optional<string> CustomId { get; set; }

[JsonProperty("url")]
public Optional<string> Url { get; set; }

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


public ButtonComponent() { }

public ButtonComponent(Discord.ButtonComponent c)
{
this.Type = c.Type;
this.Style = c.Style;
this.Label = c.Label;
this.CustomId = c.CustomId;
this.Url = c.Url;
this.Disabled = c.Disabled;

if (c.Emote != null)
{
if (c.Emote is Emote e)
{
this.Emote = new Emoji()
{
Name = e.Name,
Animated = e.Animated,
Id = e.Id,
};
}
else
{
this.Emote = new Emoji()
{
Name = c.Emote.Name
};
}
}
}
}
}

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

@@ -26,7 +26,7 @@ namespace Discord.API
public Optional<int> Flags { get; set; }

[JsonProperty("components")]
public Optional<IMessageComponent[]> Components { get; set; }
public Optional<API.ActionRowComponent[]> Components { get; set; }

public InteractionApplicationCommandCallbackData() { }
public InteractionApplicationCommandCallbackData(string text)


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

@@ -59,6 +59,6 @@ namespace Discord.API
[JsonProperty("referenced_message")]
public Optional<Message> ReferencedMessage { get; set; }
[JsonProperty("components")]
public Optional<IMessageComponent[]> Components { get; set; }
public Optional<API.ActionRowComponent[]> Components { get; set; }
}
}

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

@@ -25,7 +25,7 @@ namespace Discord.API.Rest
public Optional<MessageReference> MessageReference { get; set; }

[JsonProperty("components")]
public Optional<IMessageComponent[]> Components { get; set; }
public Optional<API.ActionRowComponent[]> Components { get; set; }
public CreateMessageParams(string content)
{
Content = content;


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

@@ -31,7 +31,7 @@ namespace Discord.API.Rest
public Optional<int> Flags { get; set; }

[JsonProperty("components")]
public Optional<IMessageComponent[]> Components { get; set; }
public Optional<API.ActionRowComponent[]> Components { get; set; }

public CreateWebhookMessageParams(string content)
{


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

@@ -1,4 +1,4 @@
#pragma warning disable CS1591
#pragma warning disable CS1591
using Newtonsoft.Json;

namespace Discord.API.Rest
@@ -10,5 +10,7 @@ namespace Discord.API.Rest
public Optional<string> Content { get; set; }
[JsonProperty("embed")]
public Optional<Embed> Embed { get; set; }
[JsonProperty("components")]
public Optional<API.ActionRowComponent[]> Components { get; set; }
}
}

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

@@ -21,7 +21,7 @@ namespace Discord.API.Rest
public Optional<Embed> Embed { get; set; }
public Optional<AllowedMentions> AllowedMentions { get; set; }
public Optional<MessageReference> MessageReference { get; set; }
public Optional<IMessageComponent[]> MessageComponent { get; set; }
public Optional<ActionRowComponent[]> MessageComponent { get; set; }
public bool IsSpoiler { get; set; } = false;

public UploadFileParams(Stream file)


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

@@ -9,9 +9,11 @@
<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.3.2</Version>
<Version>2.3.5</Version>
<PackageId>Discord.Net.Labs.Rest</PackageId>
<RepositoryUrl>https://github.com/Discord-Net-Labs/Discord.Net-Labs</RepositoryUrl>
<AssemblyVersion>2.3.4</AssemblyVersion>
<FileVersion>2.3.4</FileVersion>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Discord.Net.Core\Discord.Net.Core.csproj" />


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

@@ -944,7 +944,7 @@ namespace Discord.API
public async Task CreateInteractionResponse(InteractionResponse response, ulong interactionId, string interactionToken, RequestOptions options = null)
{
if(response.Data.IsSpecified && response.Data.Value.Content.IsSpecified)
Preconditions.AtMost(response.Data.Value.Content.Value.Length, 2000, nameof(response.Data.Value.Content));
Preconditions.AtMost(response.Data.Value.Content.Value?.Length ?? 0, 2000, nameof(response.Data.Value.Content));

options = RequestOptions.CreateOrClone(options);



+ 2
- 2
src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs View File

@@ -221,7 +221,7 @@ namespace Discord.Rest
}
}

var args = new CreateMessageParams(text) { IsTTS = isTTS, Embed = embed?.ToModel(), AllowedMentions = allowedMentions?.ToModel(), MessageReference = messageReference?.ToModel(), Components = component?.ToModel() };
var args = new CreateMessageParams(text) { IsTTS = isTTS, Embed = embed?.ToModel(), AllowedMentions = allowedMentions?.ToModel(), MessageReference = messageReference?.ToModel(), Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional<API.ActionRowComponent[]>.Unspecified };
var model = await client.ApiClient.CreateMessageAsync(channel.Id, args, options).ConfigureAwait(false);
return RestUserMessage.Create(client, channel, client.CurrentUser, model);
}
@@ -281,7 +281,7 @@ namespace Discord.Rest
}
}

var args = new UploadFileParams(stream) { Filename = filename, Content = text, IsTTS = isTTS, Embed = embed?.ToModel() ?? Optional<API.Embed>.Unspecified, AllowedMentions = allowedMentions?.ToModel() ?? Optional<API.AllowedMentions>.Unspecified, MessageReference = messageReference?.ToModel() ?? Optional<API.MessageReference>.Unspecified, MessageComponent = component?.ToModel() ?? Optional<IMessageComponent[]>.Unspecified, IsSpoiler = isSpoiler };
var args = new UploadFileParams(stream) { Filename = filename, Content = text, IsTTS = isTTS, Embed = embed?.ToModel() ?? Optional<API.Embed>.Unspecified, AllowedMentions = allowedMentions?.ToModel() ?? Optional<API.AllowedMentions>.Unspecified, MessageReference = messageReference?.ToModel() ?? Optional<API.MessageReference>.Unspecified, MessageComponent = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional<API.ActionRowComponent[]>.Unspecified, IsSpoiler = isSpoiler };
var model = await client.ApiClient.UploadFileAsync(channel.Id, args, options).ConfigureAwait(false);
return RestUserMessage.Create(client, channel, client.CurrentUser, model);
}


+ 2
- 1
src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs View File

@@ -41,7 +41,8 @@ namespace Discord.Rest
var apiArgs = new API.Rest.ModifyMessageParams
{
Content = args.Content,
Embed = args.Embed.IsSpecified ? args.Embed.Value.ToModel() : Optional.Create<API.Embed>()
Embed = args.Embed.IsSpecified ? args.Embed.Value.ToModel() : Optional.Create<API.Embed>(),
Components = args?.Components.GetValueOrDefault()?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional<API.ActionRowComponent[]>.Unspecified
};
return await client.ApiClient.ModifyMessageAsync(msg.Channel.Id, msg.Id, apiArgs, options).ConfigureAwait(false);
}


+ 10
- 3
src/Discord.Net.Rest/Entities/Messages/RestMessage.cs View File

@@ -129,9 +129,16 @@ namespace Discord.Rest

if (model.Components.IsSpecified)
{
Components = model.Components.Value.Select(x =>
(x as Newtonsoft.Json.Linq.JToken).ToObject<ActionRowComponent>()
).ToList();
Components = model.Components.Value.Select(x => new ActionRowComponent(x.Components.Select(x =>
new ButtonComponent(
x.Style,
x.Label.GetValueOrDefault(),
x.Emote.IsSpecified ? x.Emote.Value.Id.HasValue ? new Emote(x.Emote.Value.Id.Value, x.Emote.Value.Name, x.Emote.Value.Animated.GetValueOrDefault()) : new Emoji(x.Emote.Value.Name) : null,
x.CustomId.GetValueOrDefault(),
x.Url.GetValueOrDefault(),
x.Disabled.GetValueOrDefault())
).ToList()
)).ToList();
}
else
Components = new List<ActionRowComponent>();


+ 13
- 3
src/Discord.Net.WebSocket/API/Gateway/InteractionCreated.cs View File

@@ -13,6 +13,9 @@ namespace Discord.API.Gateway
[JsonProperty("id")]
public ulong Id { get; set; }

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

[JsonProperty("type")]
public InteractionType Type { get; set; }

@@ -20,18 +23,25 @@ namespace Discord.API.Gateway
public Optional<object> Data { get; set; }

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

[JsonProperty("channel_id")]
public ulong ChannelId { get; set; }
public Optional<ulong> ChannelId { get; set; }

[JsonProperty("member")]
public GuildMember Member { get; set; }
public Optional<GuildMember> Member { get; set; }

[JsonProperty("user")]
public Optional<User> User { get; set; }

[JsonProperty("token")]
public string Token { get; set; }

[JsonProperty("version")]
public int Version { get; set; }

[JsonProperty("message")]
public Optional<Message> Message { get; set; }

}
}

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

@@ -8,7 +8,7 @@
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">net461;netstandard2.0;netstandard2.1</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">netstandard2.0;netstandard2.1</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Version>2.3.2</Version>
<Version>2.3.4</Version>
<RepositoryUrl>https://github.com/Discord-Net-Labs/Discord.Net-Labs</RepositoryUrl>
<PackageProjectUrl>https://github.com/Discord-Net-Labs/Discord.Net-Labs</PackageProjectUrl>
<PackageIcon>Temporary.png</PackageIcon>


+ 19
- 12
src/Discord.Net.WebSocket/DiscordSocketClient.cs View File

@@ -1785,26 +1785,33 @@ namespace Discord.WebSocket
await _gatewayLogger.DebugAsync("Received Dispatch (INTERACTION_CREATE)").ConfigureAwait(false);

var data = (payload as JToken).ToObject<API.Gateway.InteractionCreated>(_serializer);
if (State.GetChannel(data.ChannelId) is SocketGuildChannel channel)
if (data.Member.IsSpecified && data.ChannelId.IsSpecified)
{
var guild = channel.Guild;
if (!guild.IsSynced)
if (State.GetChannel(data.ChannelId.Value) is SocketGuildChannel channel)
{
await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
return;
}
var guild = channel.Guild;
if (!guild.IsSynced)
{
await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
return;
}

var interaction = SocketInteraction.Create(this, data);
var interaction = SocketInteraction.Create(this, data);

if (this.AlwaysAcknowledgeInteractions)
await interaction.AcknowledgeAsync().ConfigureAwait(false);
if (this.AlwaysAcknowledgeInteractions)
await interaction.AcknowledgeAsync().ConfigureAwait(false);

await TimedInvokeAsync(_interactionCreatedEvent, nameof(InteractionCreated), interaction).ConfigureAwait(false);
await TimedInvokeAsync(_interactionCreatedEvent, nameof(InteractionCreated), interaction).ConfigureAwait(false);
}
else
{
await UnknownChannelAsync(type, data.ChannelId.Value).ConfigureAwait(false);
return;
}
}
else
{
await UnknownChannelAsync(type, data.ChannelId).ConfigureAwait(false);
return;
// DM TODO
}
}
break;


+ 32
- 3
src/Discord.Net.WebSocket/Entities/Interaction/Message Components/SocketMessageComponent.cs View File

@@ -10,10 +10,21 @@ using Discord.Rest;

namespace Discord.WebSocket
{
/// <summary>
/// Represents a Websocket-based interaction type for Message Components.
/// </summary>
public class SocketMessageComponent : SocketInteraction
{
/// <summary>
/// The data received with this interaction, contains the button that was clicked.
/// </summary>
new public SocketMessageComponentData Data { get; }

/// <summary>
/// The message that contained the trigger for this interaction.
/// </summary>
public SocketMessage Message { get; private set; }

internal SocketMessageComponent(DiscordSocketClient client, Model model)
: base(client, model.Id)
{
@@ -22,6 +33,8 @@ namespace Discord.WebSocket
: null;

this.Data = new SocketMessageComponentData(dataModel);


}

new internal static SocketMessageComponent Create(DiscordSocketClient client, Model model)
@@ -31,6 +44,23 @@ namespace Discord.WebSocket
return entity;
}

internal override void Update(Model model)
{
base.Update(model);

if (model.Message.IsSpecified)
{
if (this.Message == null)
{
this.Message = SocketMessage.Create(this.Discord, this.Discord.State, this.User, this.Channel, model.Message.Value);
}
else
{
this.Message.Update(this.Discord.State, model.Message.Value);
}
}
}

/// <summary>
/// Responds to an Interaction.
/// <para>
@@ -51,7 +81,6 @@ namespace Discord.WebSocket
/// </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>

public override async Task<RestUserMessage> RespondAsync(string text = null, bool isTTS = false, Embed embed = null, InteractionResponseType type = InteractionResponseType.ChannelMessageWithSource,
bool ephemeral = false, AllowedMentions allowedMentions = null, RequestOptions options = null, MessageComponent component = null)
{
@@ -94,7 +123,7 @@ namespace Discord.WebSocket
? new API.Embed[] { embed.ToModel() }
: Optional<API.Embed[]>.Unspecified,
TTS = isTTS,
Components = component?.ToModel() ?? Optional<IMessageComponent[]>.Unspecified
Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional<API.ActionRowComponent[]>.Unspecified
}
};

@@ -134,7 +163,7 @@ namespace Discord.WebSocket
Embeds = embed != null
? new API.Embed[] { embed.ToModel() }
: Optional<API.Embed[]>.Unspecified,
Components = component?.ToModel() ?? Optional<IMessageComponent[]>.Unspecified
Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional<API.ActionRowComponent[]>.Unspecified
};

if (ephemeral)


+ 3
- 0
src/Discord.Net.WebSocket/Entities/Interaction/Message Components/SocketMessageComponentData.cs View File

@@ -7,6 +7,9 @@ using Model = Discord.API.MessageComponentInteractionData;

namespace Discord.WebSocket
{
/// <summary>
/// Represents the data sent with a <see cref="InteractionType.MessageComponent"/>.
/// </summary>
public class SocketMessageComponentData
{
/// <summary>


+ 4
- 4
src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketSlashCommand.cs View File

@@ -21,7 +21,7 @@ namespace Discord.WebSocket
(model.Data.Value as JToken).ToObject<DataModel>()
: null;

Data = SocketSlashCommandData.Create(client, dataModel, model.GuildId);
Data = SocketSlashCommandData.Create(client, dataModel, model.Id);
}

new internal static SocketInteraction Create(DiscordSocketClient client, Model model)
@@ -37,7 +37,7 @@ namespace Discord.WebSocket
(model.Data.Value as JToken).ToObject<DataModel>()
: null;

this.Data.Update(data, model.GuildId);
this.Data.Update(data);

base.Update(model);
}
@@ -107,7 +107,7 @@ namespace Discord.WebSocket
? new API.Embed[] { embed.ToModel() }
: Optional<API.Embed[]>.Unspecified,
TTS = isTTS,
Components = component?.ToModel() ?? Optional<IMessageComponent[]>.Unspecified
Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional<API.ActionRowComponent[]>.Unspecified
}
};

@@ -146,7 +146,7 @@ namespace Discord.WebSocket
Embeds = embed != null
? new API.Embed[] { embed.ToModel() }
: Optional<API.Embed[]>.Unspecified,
Components = component?.ToModel() ?? Optional<IMessageComponent[]>.Unspecified
Components = component?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional<API.ActionRowComponent[]>.Unspecified
};

if (ephemeral)


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

@@ -15,27 +15,24 @@ namespace Discord.WebSocket
/// </summary>
public IReadOnlyCollection<SocketSlashCommandDataOption> Options { get; private set; }

private ulong guildId;

internal SocketSlashCommandData(DiscordSocketClient client, ulong id)
: base(client, id)
{

}

internal static SocketSlashCommandData Create(DiscordSocketClient client, Model model, ulong guildId)
internal static SocketSlashCommandData Create(DiscordSocketClient client, Model model, ulong id)
{
var entity = new SocketSlashCommandData(client, model.Id);
entity.Update(model, guildId);
entity.Update(model);
return entity;
}
internal void Update(Model model, ulong guildId)
internal void Update(Model model)
{
this.Name = model.Name;
this.guildId = guildId;

this.Options = model.Options.Any()
? model.Options.Select(x => new SocketSlashCommandDataOption(x, this.Discord, guildId)).ToImmutableArray()
? model.Options.Select(x => new SocketSlashCommandDataOption(x, this.Discord)).ToImmutableArray()
: null;
}



+ 5
- 7
src/Discord.Net.WebSocket/Entities/Interaction/Slash Commands/SocketSlashCommandDataOption.cs View File

@@ -22,18 +22,16 @@ namespace Discord.WebSocket
public IReadOnlyCollection<SocketSlashCommandDataOption> Options { get; private set; }

private DiscordSocketClient discord;
private ulong guild;

internal SocketSlashCommandDataOption() { }
internal SocketSlashCommandDataOption(Model model, DiscordSocketClient discord, ulong guild)
internal SocketSlashCommandDataOption(Model model, DiscordSocketClient discord)
{
this.Name = model.Name;
this.Value = model.Value.IsSpecified ? model.Value.Value : null;
this.discord = discord;
this.guild = guild;

this.Options = model.Options.Any()
? model.Options.Select(x => new SocketSlashCommandDataOption(x, discord, guild)).ToImmutableArray()
? model.Options.Select(x => new SocketSlashCommandDataOption(x, discord)).ToImmutableArray()
: null;
}

@@ -49,7 +47,7 @@ namespace Discord.WebSocket
{
if (option.Value is ulong id)
{
var guild = option.discord.GetGuild(option.guild);
var guild = option.discord.GetGuild(id);

if (guild == null)
return null;
@@ -64,7 +62,7 @@ namespace Discord.WebSocket
{
if (option.Value is ulong id)
{
var guild = option.discord.GetGuild(option.guild);
var guild = option.discord.GetGuild(id);

if (guild == null)
return null;
@@ -79,7 +77,7 @@ namespace Discord.WebSocket
{
if(option.Value is ulong id)
{
var guild = option.discord.GetGuild(option.guild);
var guild = option.discord.GetGuild(id);

if (guild == null)
return null;


+ 30
- 18
src/Discord.Net.WebSocket/Entities/Interaction/SocketInteraction.cs View File

@@ -14,21 +14,14 @@ namespace Discord.WebSocket
public abstract class SocketInteraction : SocketEntity<ulong>, IDiscordInteraction
{
/// <summary>
/// The <see cref="SocketGuild"/> this interaction was used in.
/// The <see cref="ISocketMessageChannel"/> this interaction was used in.
/// </summary>
public SocketGuild Guild
=> Discord.GetGuild(GuildId);
public ISocketMessageChannel Channel { get; private set; }

/// <summary>
/// The <see cref="SocketTextChannel"/> this interaction was used in.
/// The <see cref="SocketUser"/> who triggered this interaction.
/// </summary>
public SocketTextChannel Channel
=> Guild.GetTextChannel(ChannelId);

/// <summary>
/// The <see cref="SocketGuildUser"/> who triggered this interaction.
/// </summary>
public SocketGuildUser User { get; private set; }
public SocketUser User { get; private set; }

/// <summary>
/// The type of this interaction.
@@ -58,9 +51,8 @@ namespace Discord.WebSocket
public bool IsValidToken
=> CheckToken();

private ulong GuildId { get; set; }
private ulong ChannelId { get; set; }
private ulong UserId { get; set; }
private ulong? GuildId { get; set; }
private ulong? ChannelId { get; set; }

internal SocketInteraction(DiscordSocketClient client, ulong id)
: base(client, id)
@@ -83,15 +75,35 @@ namespace Discord.WebSocket
? model.Data.Value
: null;

this.GuildId = model.GuildId;
this.ChannelId = model.ChannelId;
this.GuildId = model.GuildId.ToNullable();
this.ChannelId = model.ChannelId.ToNullable();
this.Token = model.Token;
this.Version = model.Version;
this.UserId = model.Member.User.Id;
this.Type = model.Type;

if (this.User == null)
this.User = SocketGuildUser.Create(this.Guild, Discord.State, model.Member); // Change from getter.
{
if (model.Member.IsSpecified && model.GuildId.IsSpecified)
{
this.User = SocketGuildUser.Create(Discord.State.GetGuild(this.GuildId.Value), Discord.State, model.Member.Value);
}
else
{
this.User = SocketGlobalUser.Create(this.Discord, this.Discord.State, model.User.Value);
}
}

if (this.Channel == null)
{
if (model.ChannelId.IsSpecified)
{
this.Channel = Discord.State.GetChannel(model.ChannelId.Value) as ISocketMessageChannel;
}
else
{
this.Channel = Discord.State.GetDMChannel(this.User.Id);
}
}
}

/// <summary>


+ 10
- 3
src/Discord.Net.WebSocket/Entities/Messages/SocketMessage.cs View File

@@ -162,9 +162,16 @@ namespace Discord.WebSocket

if (model.Components.IsSpecified)
{
Components = model.Components.Value.Select(x =>
(x as Newtonsoft.Json.Linq.JToken).ToObject<ActionRowComponent>()
).ToList();
Components = model.Components.Value.Select(x => new ActionRowComponent(x.Components.Select(x =>
new ButtonComponent(
x.Style,
x.Label.GetValueOrDefault(),
x.Emote.IsSpecified ? x.Emote.Value.Id.HasValue ? new Emote(x.Emote.Value.Id.Value, x.Emote.Value.Name, x.Emote.Value.Animated.GetValueOrDefault()) : new Emoji(x.Emote.Value.Name) : null,
x.CustomId.GetValueOrDefault(),
x.Url.GetValueOrDefault(),
x.Disabled.GetValueOrDefault())
).ToList()
)).ToList();
}
else
Components = new List<ActionRowComponent>();


+ 10
- 10
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.3.1$suffix$</version>
<version>2.3.3$suffix$</version>
<title>Discord.Net Labs</title>
<authors>Discord.Net Contributors</authors>
<owners>quinchs</owners>
@@ -14,23 +14,23 @@
<iconUrl>https://avatars.githubusercontent.com/u/84047264</iconUrl>
<dependencies>
<group targetFramework="net461">
<dependency id="Discord.Net.Labs.Core" version="2.3.1$suffix$" />
<dependency id="Discord.Net.Labs.Rest" version="2.3.1$suffix$" />
<dependency id="Discord.Net.Labs.WebSocket" version="2.3.1$suffix$" />
<dependency id="Discord.Net.Labs.Core" version="2.3.4$suffix$" />
<dependency id="Discord.Net.Labs.Rest" version="2.3.5$suffix$" />
<dependency id="Discord.Net.Labs.WebSocket" version="2.3.4$suffix$" />
<dependency id="Discord.Net.Labs.Commands" version="2.3.1$suffix$" />
<dependency id="Discord.Net.Labs.Webhook" version="2.3.1$suffix$" />
</group>
<group targetFramework="netstandard2.0">
<dependency id="Discord.Net.Labs.Core" version="2.3.1$suffix$" />
<dependency id="Discord.Net.Labs.Rest" version="2.3.1$suffix$" />
<dependency id="Discord.Net.Labs.WebSocket" version="2.3.1$suffix$" />
<dependency id="Discord.Net.Labs.Core" version="2.3.4$suffix$" />
<dependency id="Discord.Net.Labs.Rest" version="2.3.5$suffix$" />
<dependency id="Discord.Net.Labs.WebSocket" version="2.3.4$suffix$" />
<dependency id="Discord.Net.Labs.Commands" version="2.3.1$suffix$" />
<dependency id="Discord.Net.Labs.Webhook" version="2.3.1$suffix$" />
</group>
<group targetFramework="netstandard2.1">
<dependency id="Discord.Net.Labs.Core" version="2.3.1$suffix$" />
<dependency id="Discord.Net.Labs.Rest" version="2.3.1$suffix$" />
<dependency id="Discord.Net.Labs.WebSocket" version="2.3.1$suffix$" />
<dependency id="Discord.Net.Labs.Core" version="2.3.4$suffix$" />
<dependency id="Discord.Net.Labs.Rest" version="2.3.5$suffix$" />
<dependency id="Discord.Net.Labs.WebSocket" version="2.3.4$suffix$" />
<dependency id="Discord.Net.Labs.Commands" version="2.3.1$suffix$" />
<dependency id="Discord.Net.Labs.Webhook" version="2.3.1$suffix$" />
</group>


Loading…
Cancel
Save