* feature: Add MessageFlags and AllowedMentions to Modify * Change exception messagepull/1741/head
@@ -165,6 +165,17 @@ namespace Discord | |||
IReadOnlyDictionary<IEmote, ReactionMetadata> Reactions { get; } | |||
/// <summary> | |||
/// Gets the flags related to this message. | |||
/// </summary> | |||
/// <remarks> | |||
/// This value is determined by bitwise OR-ing <see cref="MessageFlags"/> values together. | |||
/// </remarks> | |||
/// <returns> | |||
/// A message's flags, if any is associated. | |||
/// </returns> | |||
MessageFlags? Flags { get; } | |||
/// <summary> | |||
/// Adds a reaction to this message. | |||
/// </summary> | |||
/// <example> | |||
@@ -0,0 +1,36 @@ | |||
using System; | |||
namespace Discord | |||
{ | |||
[Flags] | |||
public enum MessageFlags | |||
{ | |||
/// <summary> | |||
/// Default value for flags, when none are given to a message. | |||
/// </summary> | |||
None = 0, | |||
/// <summary> | |||
/// Flag given to messages that have been published to subscribed | |||
/// channels (via Channel Following). | |||
/// </summary> | |||
Crossposted = 1 << 0, | |||
/// <summary> | |||
/// Flag given to messages that originated from a message in another | |||
/// channel (via Channel Following). | |||
/// </summary> | |||
IsCrosspost = 1 << 1, | |||
/// <summary> | |||
/// Flag given to messages that do not display any embeds. | |||
/// </summary> | |||
SuppressEmbeds = 1 << 2, | |||
/// <summary> | |||
/// Flag given to messages that the source message for this crosspost | |||
/// has been deleted (via Channel Following). | |||
/// </summary> | |||
SourceMessageDeleted = 1 << 3, | |||
/// <summary> | |||
/// Flag given to messages that came from the urgent message system. | |||
/// </summary> | |||
Urgent = 1 << 4, | |||
} | |||
} |
@@ -21,5 +21,17 @@ namespace Discord | |||
/// Gets or sets the embed the message should display. | |||
/// </summary> | |||
public Optional<Embed> Embed { get; set; } | |||
/// <summary> | |||
/// Gets or sets the flags of the message. | |||
/// </summary> | |||
/// <remarks> | |||
/// Only <see cref="MessageFlags.SuppressEmbeds"/> can be set/unset and you need to be | |||
/// the author of the message. | |||
/// </remarks> | |||
public Optional<MessageFlags?> Flags { get; set; } | |||
/// <summary> | |||
/// Gets or sets the allowed mentions of the message. | |||
/// </summary> | |||
public Optional<AllowedMentions> AllowedMentions { get; set; } | |||
} | |||
} |
@@ -1,10 +0,0 @@ | |||
using System; | |||
namespace Discord.API | |||
{ | |||
[Flags] | |||
internal enum MessageFlags : byte // probably safe to constrain this to 8 values, if not, it's internal so who cares | |||
{ | |||
Suppressed = 0x04, | |||
} | |||
} |
@@ -1,4 +1,4 @@ | |||
#pragma warning disable CS1591 | |||
#pragma warning disable CS1591 | |||
using Newtonsoft.Json; | |||
namespace Discord.API.Rest | |||
@@ -10,5 +10,9 @@ namespace Discord.API.Rest | |||
public Optional<string> Content { get; set; } | |||
[JsonProperty("embed")] | |||
public Optional<Embed> Embed { get; set; } | |||
[JsonProperty("flags")] | |||
public Optional<MessageFlags?> Flags { get; set; } | |||
[JsonProperty("allowed_mentions")] | |||
public Optional<AllowedMentions> AllowedMentions { get; set; } | |||
} | |||
} |
@@ -27,21 +27,46 @@ namespace Discord.Rest | |||
public static async Task<Model> ModifyAsync(IMessage msg, BaseDiscordClient client, Action<MessageProperties> func, | |||
RequestOptions options) | |||
{ | |||
if (msg.Author.Id != client.CurrentUser.Id) | |||
throw new InvalidOperationException("Only the author of a message may modify the message."); | |||
var args = new MessageProperties(); | |||
func(args); | |||
if (msg.Author.Id != client.CurrentUser.Id && (args.Content.IsSpecified || args.Embed.IsSpecified || args.AllowedMentions.IsSpecified)) | |||
throw new InvalidOperationException("Only the author of a message may modify the message content, embed, or allowed mentions."); | |||
bool hasText = args.Content.IsSpecified ? !string.IsNullOrEmpty(args.Content.Value) : !string.IsNullOrEmpty(msg.Content); | |||
bool hasEmbed = args.Embed.IsSpecified ? args.Embed.Value != null : msg.Embeds.Any(); | |||
if (!hasText && !hasEmbed) | |||
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<API.Embed>() | |||
Embed = args.Embed.IsSpecified ? args.Embed.Value.ToModel() : Optional.Create<API.Embed>(), | |||
Flags = args.Flags.IsSpecified ? args.Flags.Value : Optional.Create<MessageFlags?>(), | |||
AllowedMentions = args.AllowedMentions.IsSpecified ? args.AllowedMentions.Value.ToModel() : Optional.Create<API.AllowedMentions>(), | |||
}; | |||
return await client.ApiClient.ModifyMessageAsync(msg.Channel.Id, msg.Id, apiArgs, options).ConfigureAwait(false); | |||
} | |||
@@ -67,6 +67,8 @@ namespace Discord.Rest | |||
public MessageApplication Application { get; private set; } | |||
/// <inheritdoc /> | |||
public MessageReference Reference { get; private set; } | |||
/// <inheritdoc /> | |||
public MessageFlags? Flags { get; private set; } | |||
internal RestMessage(BaseDiscordClient discord, ulong id, IMessageChannel channel, IUser author, MessageSource source) | |||
: base(discord, id) | |||
@@ -124,6 +126,9 @@ namespace Discord.Rest | |||
}; | |||
} | |||
if (model.Flags.IsSpecified) | |||
Flags = model.Flags.Value; | |||
if (model.Reactions.IsSpecified) | |||
{ | |||
var value = model.Reactions.Value; | |||
@@ -13,7 +13,7 @@ namespace Discord.Rest | |||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||
public class RestUserMessage : RestMessage, IUserMessage | |||
{ | |||
private bool _isMentioningEveryone, _isTTS, _isPinned, _isSuppressed; | |||
private bool _isMentioningEveryone, _isTTS, _isPinned; | |||
private long? _editedTimestampTicks; | |||
private IUserMessage _referencedMessage; | |||
private ImmutableArray<Attachment> _attachments = ImmutableArray.Create<Attachment>(); | |||
@@ -27,7 +27,7 @@ namespace Discord.Rest | |||
/// <inheritdoc /> | |||
public override bool IsPinned => _isPinned; | |||
/// <inheritdoc /> | |||
public override bool IsSuppressed => _isSuppressed; | |||
public override bool IsSuppressed => Flags.HasValue && Flags.Value.HasFlag(MessageFlags.SuppressEmbeds); | |||
/// <inheritdoc /> | |||
public override DateTimeOffset? EditedTimestamp => DateTimeUtils.FromTicks(_editedTimestampTicks); | |||
/// <inheritdoc /> | |||
@@ -70,10 +70,6 @@ namespace Discord.Rest | |||
_editedTimestampTicks = model.EditedTimestamp.Value?.UtcTicks; | |||
if (model.MentionEveryone.IsSpecified) | |||
_isMentioningEveryone = model.MentionEveryone.Value; | |||
if (model.Flags.IsSpecified) | |||
{ | |||
_isSuppressed = model.Flags.Value.HasFlag(API.MessageFlags.Suppressed); | |||
} | |||
if (model.RoleMentions.IsSpecified) | |||
_roleMentionIds = model.RoleMentions.Value.ToImmutableArray(); | |||
@@ -58,6 +58,9 @@ namespace Discord.WebSocket | |||
/// <inheritdoc /> | |||
public MessageReference Reference { get; private set; } | |||
/// <inheritdoc /> | |||
public MessageFlags? Flags { get; private set; } | |||
/// <summary> | |||
/// Returns all attachments included in this message. | |||
/// </summary> | |||
@@ -156,6 +159,9 @@ namespace Discord.WebSocket | |||
MessageId = model.Reference.Value.MessageId | |||
}; | |||
} | |||
if (model.Flags.IsSpecified) | |||
Flags = model.Flags.Value; | |||
} | |||
/// <inheritdoc /> | |||
@@ -15,7 +15,7 @@ namespace Discord.WebSocket | |||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||
public class SocketUserMessage : SocketMessage, IUserMessage | |||
{ | |||
private bool _isMentioningEveryone, _isTTS, _isPinned, _isSuppressed; | |||
private bool _isMentioningEveryone, _isTTS, _isPinned; | |||
private long? _editedTimestampTicks; | |||
private IUserMessage _referencedMessage; | |||
private ImmutableArray<Attachment> _attachments = ImmutableArray.Create<Attachment>(); | |||
@@ -29,7 +29,7 @@ namespace Discord.WebSocket | |||
/// <inheritdoc /> | |||
public override bool IsPinned => _isPinned; | |||
/// <inheritdoc /> | |||
public override bool IsSuppressed => _isSuppressed; | |||
public override bool IsSuppressed => Flags.HasValue && Flags.Value.HasFlag(MessageFlags.SuppressEmbeds); | |||
/// <inheritdoc /> | |||
public override DateTimeOffset? EditedTimestamp => DateTimeUtils.FromTicks(_editedTimestampTicks); | |||
/// <inheritdoc /> | |||
@@ -74,10 +74,6 @@ namespace Discord.WebSocket | |||
_editedTimestampTicks = model.EditedTimestamp.Value?.UtcTicks; | |||
if (model.MentionEveryone.IsSpecified) | |||
_isMentioningEveryone = model.MentionEveryone.Value; | |||
if (model.Flags.IsSpecified) | |||
{ | |||
_isSuppressed = model.Flags.Value.HasFlag(API.MessageFlags.Suppressed); | |||
} | |||
if (model.RoleMentions.IsSpecified) | |||
_roleMentions = model.RoleMentions.Value.Select(x => guild.GetRole(x)).ToImmutableArray(); | |||