Skip to content

Commit

Permalink
feature: Add inline replies (#1659)
Browse files Browse the repository at this point in the history
* Add inline replies

* Missed a few things

* Change xml docs, IUserMessage, and other changes

* Missed one when changing

* Fix referencedMessage author
  • Loading branch information
SubZero0 authored Nov 22, 2020
1 parent 25d5d36 commit e3850e1
Show file tree
Hide file tree
Showing 32 changed files with 239 additions and 132 deletions.
5 changes: 3 additions & 2 deletions src/Discord.Net.Commands/ModuleBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ public abstract class ModuleBase<T> : IModuleBase
/// Specifies if notifications are sent for mentioned users and roles in the <paramref name="message"/>.
/// If <c>null</c>, all mentioned roles and users will be notified.
/// </param>
protected virtual async Task<IUserMessage> ReplyAsync(string message = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null)
/// <param name="messageReference">The message references to be included. Used to reply to specific messages.</param>
protected virtual async Task<IUserMessage> ReplyAsync(string message = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null)
{
return await Context.Channel.SendMessageAsync(message, isTTS, embed, options, allowedMentions).ConfigureAwait(false);
return await Context.Channel.SendMessageAsync(message, isTTS, embed, options, allowedMentions, messageReference).ConfigureAwait(false);
}
/// <summary>
/// The method to execute before executing the command.
Expand Down
9 changes: 6 additions & 3 deletions src/Discord.Net.Core/Entities/Channels/IMessageChannel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@ public interface IMessageChannel : IChannel
/// Specifies if notifications are sent for mentioned users and roles in the message <paramref name="text"/>.
/// If <c>null</c>, all mentioned roles and users will be notified.
/// </param>
/// <param name="messageReference">The message references to be included. Used to reply to specific messages.</param>
/// <returns>
/// A task that represents an asynchronous send operation for delivering the message. The task result
/// contains the sent message.
/// </returns>
Task<IUserMessage> SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null);
Task<IUserMessage> SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null);
/// <summary>
/// Sends a file to this message channel with an optional caption.
/// </summary>
Expand Down Expand Up @@ -63,11 +64,12 @@ public interface IMessageChannel : IChannel
/// Specifies if notifications are sent for mentioned users and roles in the message <paramref name="text"/>.
/// If <c>null</c>, all mentioned roles and users will be notified.
/// </param>
/// <param name="messageReference">The message references to be included. Used to reply to specific messages.</param>
/// <returns>
/// A task that represents an asynchronous send operation for delivering the message. The task result
/// contains the sent message.
/// </returns>
Task<IUserMessage> SendFileAsync(string filePath, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null);
Task<IUserMessage> SendFileAsync(string filePath, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null);
/// <summary>
/// Sends a file to this message channel with an optional caption.
/// </summary>
Expand Down Expand Up @@ -96,11 +98,12 @@ public interface IMessageChannel : IChannel
/// Specifies if notifications are sent for mentioned users and roles in the message <paramref name="text"/>.
/// If <c>null</c>, all mentioned roles and users will be notified.
/// </param>
/// <param name="messageReference">The message references to be included. Used to reply to specific messages.</param>
/// <returns>
/// A task that represents an asynchronous send operation for delivering the message. The task result
/// contains the sent message.
/// </returns>
Task<IUserMessage> SendFileAsync(Stream stream, string filename, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null);
Task<IUserMessage> SendFileAsync(Stream stream, string filename, string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, bool isSpoiler = false, AllowedMentions allowedMentions = null, MessageReference messageReference = null);

/// <summary>
/// Gets a message from this message channel.
Expand Down
8 changes: 8 additions & 0 deletions src/Discord.Net.Core/Entities/Messages/AllowedMentions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ public class AllowedMentions
/// </summary>
public List<ulong> UserIds { get; set; } = new List<ulong>();

/// <summary>
/// Gets or sets whether to mention the author of the message you are replying to or not.
/// </summary>
/// <remarks>
/// Specifically for inline replies.
/// </remarks>
public bool? MentionRepliedUser { get; set; } = null;

/// <summary>
/// Initializes a new instance of the <see cref="AllowedMentions"/> class.
/// </summary>
Expand Down
6 changes: 3 additions & 3 deletions src/Discord.Net.Core/Entities/Messages/IMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,11 @@ public interface IMessage : ISnowflakeEntity, IDeletable
MessageApplication Application { get; }

/// <summary>
/// Gets the reference to the original message if it was crossposted.
/// Gets the reference to the original message if it is a crosspost, channel follow add, pin, or reply message.
/// </summary>
/// <remarks>
/// Sent with Cross-posted messages, meaning they were published from news channels
/// and received by subscriber channels.
/// Sent with cross-posted messages, meaning they were published from news channels
/// and received by subscriber channels, channel follow adds, pins, and message replies.
/// </remarks>
/// <returns>
/// A message's reference, if any is associated.
Expand Down
9 changes: 8 additions & 1 deletion src/Discord.Net.Core/Entities/Messages/IUserMessage.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace Discord
Expand All @@ -9,6 +8,14 @@ namespace Discord
/// </summary>
public interface IUserMessage : IMessage
{
/// <summary>
/// Gets the referenced message if it is a crosspost, channel follow add, pin, or reply message.
/// </summary>
/// <returns>
/// The referenced message, if any is associated and still exists.
/// </returns>
IUserMessage ReferencedMessage { get; }

/// <summary>
/// Modifies this message.
/// </summary>
Expand Down
27 changes: 25 additions & 2 deletions src/Discord.Net.Core/Entities/Messages/MessageReference.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
namespace Discord
{
/// <summary>
/// Contains the IDs sent from a crossposted message.
/// Contains the IDs sent from a crossposted message or inline reply.
/// </summary>
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class MessageReference
Expand All @@ -16,13 +16,36 @@ public class MessageReference
/// <summary>
/// Gets the Channel ID of the original message.
/// </summary>
public ulong ChannelId { get; internal set; }
/// <remarks>
/// It only will be the default value (zero) if it was instantiated with a <see langword="null"/> in the constructor.
/// </remarks>
public ulong ChannelId { get => InternalChannelId.GetValueOrDefault(); }
internal Optional<ulong> InternalChannelId;

/// <summary>
/// Gets the Guild ID of the original message.
/// </summary>
public Optional<ulong> GuildId { get; internal set; }

/// <summary>
/// Initializes a new instance of the <see cref="MessageReference"/> class.
/// </summary>
/// <param name="messageId">
/// The ID of the message that will be referenced. Used to reply to specific messages and the only parameter required for it.
/// </param>
/// <param name="channelId">
/// The ID of the channel that will be referenced. It will be validated if sent.
/// </param>
/// <param name="guildId">
/// The ID of the guild that will be referenced. It will be validated if sent.
/// </param>
public MessageReference(ulong? messageId = null, ulong? channelId = null, ulong? guildId = null)
{
MessageId = messageId ?? Optional.Create<ulong>();
InternalChannelId = channelId ?? Optional.Create<ulong>();
GuildId = guildId ?? Optional.Create<ulong>();
}

private string DebuggerDisplay
=> $"Channel ID: ({ChannelId}){(GuildId.IsSpecified ? $", Guild ID: ({GuildId.Value})" : "")}" +
$"{(MessageId.IsSpecified ? $", Message ID: ({MessageId.Value})" : "")}";
Expand Down
7 changes: 7 additions & 0 deletions src/Discord.Net.Core/Entities/Messages/MessageType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,12 @@ public enum MessageType
/// The message for when a news channel subscription is added to a text channel.
/// </summary>
ChannelFollowAdd = 12,
/// <summary>
/// The message is an inline reply.
/// </summary>
/// <remarks>
/// Only available in API v8.
/// </remarks>
Reply = 19,
}
}
2 changes: 1 addition & 1 deletion src/Discord.Net.Core/Entities/Users/IGuildUser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public interface IGuildUser : IUser, IVoiceState
/// </summary>
/// <example>
/// <para>The following example checks if the current user has the ability to send a message with attachment in
/// this channel; if so, uploads a file via <see cref="IMessageChannel.SendFileAsync(string, string, bool, Embed, RequestOptions, bool, AllowedMentions)"/>.</para>
/// this channel; if so, uploads a file via <see cref="IMessageChannel.SendFileAsync(string, string, bool, Embed, RequestOptions, bool, AllowedMentions, MessageReference)"/>.</para>
/// <code language="cs">
/// if (currentUser?.GetPermissions(targetChannel)?.AttachFiles)
/// await targetChannel.SendFileAsync("fortnite.png");
Expand Down
20 changes: 20 additions & 0 deletions src/Discord.Net.Core/Extensions/MessageExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,5 +71,25 @@ public static async Task RemoveReactionsAsync(this IUserMessage msg, IUser user,
foreach (var rxn in reactions)
await msg.RemoveReactionAsync(rxn, user, options).ConfigureAwait(false);
}

/// <summary>
/// Sends an inline reply that references a message.
/// </summary>
/// <param name="text">The message to be sent.</param>
/// <param name="isTTS">Determines whether the message should be read aloud by Discord or not.</param>
/// <param name="embed">The <see cref="Discord.EmbedType.Rich"/> <see cref="Embed"/> to be sent.</param>
/// <param name="allowedMentions">
/// Specifies if notifications are sent for mentioned users and roles in the message <paramref name="text"/>.
/// If <c>null</c>, all mentioned roles and users will be notified.
/// </param>
/// <param name="options">The options to be used when sending the request.</param>
/// <returns>
/// A task that represents an asynchronous send operation for delivering the message. The task result
/// contains the sent message.
/// </returns>
public static async Task<IUserMessage> ReplyAsync(this IUserMessage msg, string text = null, bool isTTS = false, Embed embed = null, AllowedMentions allowedMentions = null, RequestOptions options = null)
{
return await msg.Channel.SendMessageAsync(text, isTTS, embed, options, allowedMentions, new MessageReference(messageId: msg.Id)).ConfigureAwait(false);
}
}
}
2 changes: 2 additions & 0 deletions src/Discord.Net.Rest/API/Common/Message.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,7 @@ internal class Message
public Optional<MessageFlags> Flags { get; set; }
[JsonProperty("allowed_mentions")]
public Optional<AllowedMentions> AllowedMentions { get; set; }
[JsonProperty("referenced_message")]
public Optional<Message> ReferencedMessage { get; set; }
}
}
2 changes: 1 addition & 1 deletion src/Discord.Net.Rest/API/Common/MessageReference.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ internal class MessageReference
public Optional<ulong> MessageId { get; set; }

[JsonProperty("channel_id")]
public ulong ChannelId { get; set; }
public Optional<ulong> ChannelId { get; set; } // Optional when sending, always present when receiving

[JsonProperty("guild_id")]
public Optional<ulong> GuildId { get; set; }
Expand Down
2 changes: 2 additions & 0 deletions src/Discord.Net.Rest/API/Rest/CreateMessageParams.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ internal class CreateMessageParams
public Optional<Embed> Embed { get; set; }
[JsonProperty("allowed_mentions")]
public Optional<AllowedMentions> AllowedMentions { get; set; }
[JsonProperty("message_reference")]
public Optional<MessageReference> MessageReference { get; set; }

public CreateMessageParams(string content)
{
Expand Down
1 change: 1 addition & 0 deletions src/Discord.Net.Rest/API/Rest/UploadFileParams.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ internal class UploadFileParams
public Optional<bool> IsTTS { get; set; }
public Optional<Embed> Embed { get; set; }
public Optional<AllowedMentions> AllowedMentions { get; set; }
public Optional<MessageReference> MessageReference { get; set; }
public bool IsSpoiler { get; set; } = false;

public UploadFileParams(Stream file)
Expand Down
Loading

0 comments on commit e3850e1

Please sign in to comment.