diff --git a/src/Discord.Net.Core/Entities/Channels/IMessageChannel.cs b/src/Discord.Net.Core/Entities/Channels/IMessageChannel.cs
index abd20e4f0..e60eb9c13 100644
--- a/src/Discord.Net.Core/Entities/Channels/IMessageChannel.cs
+++ b/src/Discord.Net.Core/Entities/Channels/IMessageChannel.cs
@@ -257,6 +257,21 @@ namespace Discord
///
Task DeleteMessageAsync(IMessage message, RequestOptions options = null);
+ ///
+ /// Modifies a message.
+ ///
+ ///
+ /// This method modifies this message with the specified properties. To see an example of this
+ /// method and what properties are available, please refer to .
+ ///
+ /// The snowflake identifier of the message that would be changed.
+ /// A delegate containing the properties to modify the message with.
+ /// The options to be used when sending the request.
+ ///
+ /// A task that represents the asynchronous modification operation.
+ ///
+ Task ModifyMessageAsync(ulong messageId, Action func, RequestOptions options = null);
+
///
/// Broadcasts the "user is typing" message to all users in this channel, lasting 10 seconds.
///
diff --git a/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs b/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs
index c1d0ac294..7c4edb43e 100644
--- a/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs
+++ b/src/Discord.Net.Rest/Entities/Channels/ChannelHelper.cs
@@ -286,6 +286,13 @@ namespace Discord.Rest
return RestUserMessage.Create(client, channel, client.CurrentUser, model);
}
+ public static async Task ModifyMessageAsync(IMessageChannel channel, ulong messageId, Action func,
+ BaseDiscordClient client, RequestOptions options)
+ {
+ var msgModel = await MessageHelper.ModifyAsync(channel.Id, messageId, client, func, options).ConfigureAwait(false);
+ return RestUserMessage.Create(client, channel, msgModel.Author.IsSpecified ? RestUser.Create(client, msgModel.Author.Value) : client.CurrentUser, msgModel);
+ }
+
public static Task DeleteMessageAsync(IMessageChannel channel, ulong messageId, BaseDiscordClient client,
RequestOptions options)
=> MessageHelper.DeleteAsync(channel.Id, messageId, client, options);
diff --git a/src/Discord.Net.Rest/Entities/Channels/RestDMChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestDMChannel.cs
index d59a10fb5..6ccfd204c 100644
--- a/src/Discord.Net.Rest/Entities/Channels/RestDMChannel.cs
+++ b/src/Discord.Net.Rest/Entities/Channels/RestDMChannel.cs
@@ -135,6 +135,10 @@ namespace Discord.Rest
public Task DeleteMessageAsync(IMessage message, RequestOptions options = null)
=> ChannelHelper.DeleteMessageAsync(this, message.Id, Discord, options);
+ ///
+ public async Task ModifyMessageAsync(ulong messageId, Action func, RequestOptions options = null)
+ => await ChannelHelper.ModifyMessageAsync(this, messageId, func, Discord, options).ConfigureAwait(false);
+
///
public Task TriggerTypingAsync(RequestOptions options = null)
=> ChannelHelper.TriggerTypingAsync(this, Discord, options);
diff --git a/src/Discord.Net.Rest/Entities/Channels/RestGroupChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestGroupChannel.cs
index 666d6a4f4..2b0ab8b42 100644
--- a/src/Discord.Net.Rest/Entities/Channels/RestGroupChannel.cs
+++ b/src/Discord.Net.Rest/Entities/Channels/RestGroupChannel.cs
@@ -93,6 +93,10 @@ namespace Discord.Rest
public Task DeleteMessageAsync(IMessage message, RequestOptions options = null)
=> ChannelHelper.DeleteMessageAsync(this, message.Id, Discord, options);
+ ///
+ public async Task ModifyMessageAsync(ulong messageId, Action func, RequestOptions options = null)
+ => await ChannelHelper.ModifyMessageAsync(this, messageId, func, Discord, options).ConfigureAwait(false);
+
///
/// Message content is too long, length must be less or equal to .
public Task SendMessageAsync(string text = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null)
diff --git a/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs
index fdc4b7988..c6d0b0509 100644
--- a/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs
+++ b/src/Discord.Net.Rest/Entities/Channels/RestTextChannel.cs
@@ -152,6 +152,10 @@ namespace Discord.Rest
public Task DeleteMessagesAsync(IEnumerable messageIds, RequestOptions options = null)
=> ChannelHelper.DeleteMessagesAsync(this, Discord, messageIds, options);
+ ///
+ public async Task ModifyMessageAsync(ulong messageId, Action func, RequestOptions options = null)
+ => await ChannelHelper.ModifyMessageAsync(this, messageId, func, Discord, options).ConfigureAwait(false);
+
///
public Task TriggerTypingAsync(RequestOptions options = null)
=> ChannelHelper.TriggerTypingAsync(this, Discord, options);
diff --git a/src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs b/src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs
index b2584c8c1..1bc284836 100644
--- a/src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs
+++ b/src/Discord.Net.Rest/Entities/Messages/MessageHelper.cs
@@ -71,6 +71,48 @@ namespace Discord.Rest
return await client.ApiClient.ModifyMessageAsync(msg.Channel.Id, msg.Id, apiArgs, options).ConfigureAwait(false);
}
+ public static async Task ModifyAsync(ulong channelId, ulong msgId, BaseDiscordClient client, Action func,
+ RequestOptions options)
+ {
+ var args = new MessageProperties();
+ func(args);
+
+ if ((args.Content.IsSpecified && string.IsNullOrEmpty(args.Content.Value)) && (args.Embed.IsSpecified && args.Embed.Value == null))
+ Preconditions.NotNullOrEmpty(args.Content.IsSpecified ? args.Content.Value : string.Empty, nameof(args.Content));
+
+ if (args.AllowedMentions.IsSpecified)
+ {
+ AllowedMentions allowedMentions = args.AllowedMentions.Value;
+ Preconditions.AtMost(allowedMentions?.RoleIds?.Count ?? 0, 100, nameof(allowedMentions.RoleIds), "A max of 100 role Ids are allowed.");
+ Preconditions.AtMost(allowedMentions?.UserIds?.Count ?? 0, 100, nameof(allowedMentions.UserIds), "A max of 100 user Ids are allowed.");
+
+ // check that user flag and user Id list are exclusive, same with role flag and role Id list
+ if (allowedMentions != null && allowedMentions.AllowedTypes.HasValue)
+ {
+ if (allowedMentions.AllowedTypes.Value.HasFlag(AllowedMentionTypes.Users) &&
+ allowedMentions.UserIds != null && allowedMentions.UserIds.Count > 0)
+ {
+ throw new ArgumentException("The Users flag is mutually exclusive with the list of User Ids.", nameof(allowedMentions));
+ }
+
+ if (allowedMentions.AllowedTypes.Value.HasFlag(AllowedMentionTypes.Roles) &&
+ allowedMentions.RoleIds != null && allowedMentions.RoleIds.Count > 0)
+ {
+ throw new ArgumentException("The Roles flag is mutually exclusive with the list of Role Ids.", nameof(allowedMentions));
+ }
+ }
+ }
+
+ var apiArgs = new API.Rest.ModifyMessageParams
+ {
+ Content = args.Content,
+ Embed = args.Embed.IsSpecified ? args.Embed.Value.ToModel() : Optional.Create(),
+ Flags = args.Flags.IsSpecified ? args.Flags.Value : Optional.Create(),
+ AllowedMentions = args.AllowedMentions.IsSpecified ? args.AllowedMentions.Value.ToModel() : Optional.Create(),
+ };
+ return await client.ApiClient.ModifyMessageAsync(channelId, msgId, apiArgs, options).ConfigureAwait(false);
+ }
+
public static Task DeleteAsync(IMessage msg, BaseDiscordClient client, RequestOptions options)
=> DeleteAsync(msg.Channel.Id, msg.Id, client, options);
diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketDMChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketDMChannel.cs
index c123a9d4e..5de417036 100644
--- a/src/Discord.Net.WebSocket/Entities/Channels/SocketDMChannel.cs
+++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketDMChannel.cs
@@ -152,6 +152,10 @@ namespace Discord.WebSocket
public Task DeleteMessageAsync(IMessage message, RequestOptions options = null)
=> ChannelHelper.DeleteMessageAsync(this, message.Id, Discord, options);
+ ///
+ public async Task ModifyMessageAsync(ulong messageId, Action func, RequestOptions options = null)
+ => await ChannelHelper.ModifyMessageAsync(this, messageId, func, Discord, options).ConfigureAwait(false);
+
///
public Task TriggerTypingAsync(RequestOptions options = null)
=> ChannelHelper.TriggerTypingAsync(this, Discord, options);
diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketGroupChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketGroupChannel.cs
index dc5ac4222..ab8c76aeb 100644
--- a/src/Discord.Net.WebSocket/Entities/Channels/SocketGroupChannel.cs
+++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketGroupChannel.cs
@@ -180,6 +180,10 @@ namespace Discord.WebSocket
public Task DeleteMessageAsync(IMessage message, RequestOptions options = null)
=> ChannelHelper.DeleteMessageAsync(this, message.Id, Discord, options);
+ ///
+ public async Task ModifyMessageAsync(ulong messageId, Action func, RequestOptions options = null)
+ => await ChannelHelper.ModifyMessageAsync(this, messageId, func, Discord, options).ConfigureAwait(false);
+
///
public Task TriggerTypingAsync(RequestOptions options = null)
=> ChannelHelper.TriggerTypingAsync(this, Discord, options);
diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs
index d7d918f9f..71a20c198 100644
--- a/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs
+++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketTextChannel.cs
@@ -180,6 +180,10 @@ namespace Discord.WebSocket
public Task DeleteMessagesAsync(IEnumerable messageIds, RequestOptions options = null)
=> ChannelHelper.DeleteMessagesAsync(this, Discord, messageIds, options);
+ ///
+ public async Task ModifyMessageAsync(ulong messageId, Action func, RequestOptions options = null)
+ => await ChannelHelper.ModifyMessageAsync(this, messageId, func, Discord, options).ConfigureAwait(false);
+
///
public Task DeleteMessageAsync(ulong messageId, RequestOptions options = null)
=> ChannelHelper.DeleteMessageAsync(this, messageId, Discord, options);
diff --git a/test/Discord.Net.Tests.Unit/MockedEntities/MockedDMChannel.cs b/test/Discord.Net.Tests.Unit/MockedEntities/MockedDMChannel.cs
index f169fb717..593b9201a 100644
--- a/test/Discord.Net.Tests.Unit/MockedEntities/MockedDMChannel.cs
+++ b/test/Discord.Net.Tests.Unit/MockedEntities/MockedDMChannel.cs
@@ -33,6 +33,11 @@ namespace Discord
throw new NotImplementedException();
}
+ public Task ModifyMessageAsync(ulong messageId, Action func, RequestOptions options = null)
+ {
+ throw new NotImplementedException();
+ }
+
public IDisposable EnterTypingState(RequestOptions options = null)
{
throw new NotImplementedException();
diff --git a/test/Discord.Net.Tests.Unit/MockedEntities/MockedGroupChannel.cs b/test/Discord.Net.Tests.Unit/MockedEntities/MockedGroupChannel.cs
index e662d628a..6daf6a9c8 100644
--- a/test/Discord.Net.Tests.Unit/MockedEntities/MockedGroupChannel.cs
+++ b/test/Discord.Net.Tests.Unit/MockedEntities/MockedGroupChannel.cs
@@ -31,6 +31,11 @@ namespace Discord
throw new NotImplementedException();
}
+ public Task ModifyMessageAsync(ulong messageId, Action func, RequestOptions options = null)
+ {
+ throw new NotImplementedException();
+ }
+
public Task DisconnectAsync()
{
throw new NotImplementedException();
diff --git a/test/Discord.Net.Tests.Unit/MockedEntities/MockedTextChannel.cs b/test/Discord.Net.Tests.Unit/MockedEntities/MockedTextChannel.cs
index fbaaf9a18..51aece5f2 100644
--- a/test/Discord.Net.Tests.Unit/MockedEntities/MockedTextChannel.cs
+++ b/test/Discord.Net.Tests.Unit/MockedEntities/MockedTextChannel.cs
@@ -77,6 +77,11 @@ namespace Discord
throw new NotImplementedException();
}
+ public Task ModifyMessageAsync(ulong messageId, Action func, RequestOptions options = null)
+ {
+ throw new NotImplementedException();
+ }
+
public IDisposable EnterTypingState(RequestOptions options = null)
{
throw new NotImplementedException();