diff --git a/src/Discord.Net.Core/Entities/Messages/Mentions/ChannelMentionHandling.cs b/src/Discord.Net.Core/Entities/Messages/Mentions/ChannelMentionHandling.cs
index 39f9baa6a..ea1b91688 100644
--- a/src/Discord.Net.Core/Entities/Messages/Mentions/ChannelMentionHandling.cs
+++ b/src/Discord.Net.Core/Entities/Messages/Mentions/ChannelMentionHandling.cs
@@ -4,6 +4,7 @@
{
Ignore = 0,
Remove,
- Name
+ Name,
+ Sanitize
}
}
diff --git a/src/Discord.Net.Core/Entities/Messages/Mentions/RoleMentionHandling.cs b/src/Discord.Net.Core/Entities/Messages/Mentions/RoleMentionHandling.cs
index 466cf1fd8..94d4a382f 100644
--- a/src/Discord.Net.Core/Entities/Messages/Mentions/RoleMentionHandling.cs
+++ b/src/Discord.Net.Core/Entities/Messages/Mentions/RoleMentionHandling.cs
@@ -4,6 +4,7 @@
{
Ignore = 0,
Remove,
- Name
+ Name,
+ Sanitize
}
}
diff --git a/src/Discord.Net.Core/Entities/Messages/Mentions/UserMentionHandling.cs b/src/Discord.Net.Core/Entities/Messages/Mentions/UserMentionHandling.cs
index b31a994a2..42914f393 100644
--- a/src/Discord.Net.Core/Entities/Messages/Mentions/UserMentionHandling.cs
+++ b/src/Discord.Net.Core/Entities/Messages/Mentions/UserMentionHandling.cs
@@ -5,6 +5,7 @@
Ignore = 0,
Remove,
Name,
- NameAndDiscriminator
+ NameAndDiscriminator,
+ Sanitize
}
}
diff --git a/src/Discord.Net.Core/Utils/MentionUtils.cs b/src/Discord.Net.Core/Utils/MentionUtils.cs
index acfe35a03..51463cdae 100644
--- a/src/Discord.Net.Core/Utils/MentionUtils.cs
+++ b/src/Discord.Net.Core/Utils/MentionUtils.cs
@@ -1,14 +1,27 @@
using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
using System.Globalization;
+using System.Linq;
+using System.Text.RegularExpressions;
namespace Discord
{
public static class MentionUtils
{
+ private const char SanitizeChar = '\x200b';
+
+ private static readonly Regex _userRegex = new Regex(@"<@!?([0-9]+)>", RegexOptions.Compiled);
+ private static readonly Regex _channelRegex = new Regex(@"<#([0-9]+)>", RegexOptions.Compiled);
+ private static readonly Regex _roleRegex = new Regex(@"<@&([0-9]+)>", RegexOptions.Compiled);
+
//If the system can't be positive a user doesn't have a nickname, assume useNickname = true (source: Jake)
- public static string MentionUser(ulong id) => MentionsHelper.MentionUser(id, true);
- public static string MentionChannel(ulong id) => MentionsHelper.MentionChannel(id);
- public static string MentionRole(ulong id) => MentionsHelper.MentionRole(id);
+ internal static string MentionUser(string id, bool useNickname = true) => useNickname ? $"<@!{id}>" : $"<@{id}>";
+ public static string MentionUser(ulong id) => MentionUser(id.ToString(), true);
+ internal static string MentionChannel(string id) => $"<#{id}>";
+ public static string MentionChannel(ulong id) => MentionChannel(id.ToString());
+ internal static string MentionRole(string id) => $"<@&{id}>";
+ public static string MentionRole(ulong id) => MentionRole(id.ToString());
/// Parses a provided user mention string.
public static ulong ParseUser(string mentionText)
@@ -81,5 +94,191 @@ namespace Discord
roleId = 0;
return false;
}
+
+ internal static ImmutableArray GetUserMentions(string text, IMessageChannel channel, IReadOnlyCollection mentionedUsers)
+ where TUser : class, IUser
+ {
+ var matches = _userRegex.Matches(text);
+ var builder = ImmutableArray.CreateBuilder(matches.Count);
+ foreach (var match in matches.OfType())
+ {
+ ulong id;
+ if (ulong.TryParse(match.Groups[1].Value, NumberStyles.None, CultureInfo.InvariantCulture, out id))
+ {
+ TUser user = null;
+
+ //Verify this user was actually mentioned
+ foreach (var userMention in mentionedUsers)
+ {
+ if (userMention.Id == id)
+ {
+ user = channel?.GetUserAsync(id, CacheMode.CacheOnly).GetAwaiter().GetResult() as TUser;
+ if (user == null) //User not found, fallback to basic mention info
+ user = userMention;
+ break;
+ }
+ }
+
+ if (user != null)
+ builder.Add(user);
+ }
+ }
+ return builder.ToImmutable();
+ }
+ internal static ImmutableArray GetChannelMentions(string text, IGuild guild)
+ {
+ var matches = _channelRegex.Matches(text);
+ var builder = ImmutableArray.CreateBuilder(matches.Count);
+ foreach (var match in matches.OfType())
+ {
+ ulong id;
+ if (ulong.TryParse(match.Groups[1].Value, NumberStyles.None, CultureInfo.InvariantCulture, out id))
+ builder.Add(id);
+ }
+ return builder.ToImmutable();
+ }
+ internal static ImmutableArray GetRoleMentions(string text, IGuild guild)
+ where TRole : class, IRole
+ {
+ if (guild == null)
+ return ImmutableArray.Create();
+
+ var matches = _roleRegex.Matches(text);
+ var builder = ImmutableArray.CreateBuilder(matches.Count);
+ foreach (var match in matches.OfType())
+ {
+ ulong id;
+ if (ulong.TryParse(match.Groups[1].Value, NumberStyles.None, CultureInfo.InvariantCulture, out id))
+ {
+ var role = guild.GetRole(id) as TRole;
+ if (role != null)
+ builder.Add(role);
+ }
+ }
+ return builder.ToImmutable();
+ }
+
+ internal static string ResolveUserMentions(string text, IMessageChannel channel, IReadOnlyCollection mentions, UserMentionHandling mode)
+ {
+ if (mode == UserMentionHandling.Ignore) return text;
+
+ return _userRegex.Replace(text, new MatchEvaluator(e =>
+ {
+ ulong id;
+ if (ulong.TryParse(e.Groups[1].Value, NumberStyles.None, CultureInfo.InvariantCulture, out id))
+ {
+ IUser user = null;
+ foreach (var mention in mentions)
+ {
+ if (mention.Id == id)
+ {
+ user = mention;
+ break;
+ }
+ }
+ if (user != null)
+ {
+ string name = user.Username;
+
+ var guildUser = user as IGuildUser;
+ if (e.Value[2] == '!')
+ {
+ if (guildUser != null && guildUser.Nickname != null)
+ name = guildUser.Nickname;
+ }
+
+ switch (mode)
+ {
+ case UserMentionHandling.Name:
+ return $"@{name}";
+ case UserMentionHandling.NameAndDiscriminator:
+ return $"@{name}#{user.Discriminator}";
+ case UserMentionHandling.Sanitize:
+ return MentionUser($"{SanitizeChar}{id}");
+ case UserMentionHandling.Remove:
+ default:
+ return "";
+ }
+ }
+ }
+ return e.Value;
+ }));
+ }
+ internal static string ResolveChannelMentions(string text, IGuild guild, ChannelMentionHandling mode)
+ {
+ if (mode == ChannelMentionHandling.Ignore) return text;
+
+ return _channelRegex.Replace(text, new MatchEvaluator(e =>
+ {
+ ulong id;
+ if (ulong.TryParse(e.Groups[1].Value, NumberStyles.None, CultureInfo.InvariantCulture, out id))
+ {
+ switch (mode)
+ {
+ case ChannelMentionHandling.Name:
+ IGuildChannel channel = null;
+ channel = guild.GetChannelAsync(id, CacheMode.CacheOnly).GetAwaiter().GetResult();
+ if (channel != null)
+ return $"#{channel.Name}";
+ else
+ return $"#deleted-channel";
+ case ChannelMentionHandling.Sanitize:
+ return MentionChannel($"{SanitizeChar}{id}");
+ case ChannelMentionHandling.Remove:
+ default:
+ return "";
+ }
+ }
+ return e.Value;
+ }));
+ }
+ internal static string ResolveRoleMentions(string text, IReadOnlyCollection mentions, RoleMentionHandling mode)
+ {
+ if (mode == RoleMentionHandling.Ignore) return text;
+
+ return _roleRegex.Replace(text, new MatchEvaluator(e =>
+ {
+ ulong id;
+ if (ulong.TryParse(e.Groups[1].Value, NumberStyles.None, CultureInfo.InvariantCulture, out id))
+ {
+ switch (mode)
+ {
+ case RoleMentionHandling.Name:
+ IRole role = null;
+ foreach (var mention in mentions)
+ {
+ if (mention.Id == id)
+ {
+ role = mention;
+ break;
+ }
+ }
+ if (role != null)
+ return $"{role.Name}";
+ else
+ return $"deleted-role";
+ case RoleMentionHandling.Sanitize:
+ return MentionRole($"{SanitizeChar}{id}");
+ case RoleMentionHandling.Remove:
+ default:
+ return "";
+ }
+ }
+ return e.Value;
+ }));
+ }
+ internal static string ResolveEveryoneMentions(string text, EveryoneMentionHandling mode)
+ {
+ if (mode == EveryoneMentionHandling.Ignore) return text;
+
+ switch (mode)
+ {
+ case EveryoneMentionHandling.Sanitize:
+ return text.Replace("@everyone", $"@{SanitizeChar}everyone").Replace("@here", $"@{SanitizeChar}here");
+ case EveryoneMentionHandling.Remove:
+ default:
+ return text.Replace("@everyone", "").Replace("@here", "");
+ }
+ }
}
}
diff --git a/src/Discord.Net.Core/Utils/MentionsHelper.cs b/src/Discord.Net.Core/Utils/MentionsHelper.cs
deleted file mode 100644
index 269e235aa..000000000
--- a/src/Discord.Net.Core/Utils/MentionsHelper.cs
+++ /dev/null
@@ -1,198 +0,0 @@
-using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.Globalization;
-using System.Linq;
-using System.Text.RegularExpressions;
-
-namespace Discord
-{
- internal static class MentionsHelper
- {
- private static readonly Regex _userRegex = new Regex(@"<@!?([0-9]+)>", RegexOptions.Compiled);
- private static readonly Regex _channelRegex = new Regex(@"<#([0-9]+)>", RegexOptions.Compiled);
- private static readonly Regex _roleRegex = new Regex(@"<@&([0-9]+)>", RegexOptions.Compiled);
-
- //If the system can't be positive a user doesn't have a nickname, assume useNickname = true (source: Jake)
- internal static string MentionUser(ulong id, bool useNickname = true) => useNickname ? $"<@!{id}>" : $"<@{id}>";
- internal static string MentionChannel(ulong id) => $"<#{id}>";
- internal static string MentionRole(ulong id) => $"<@&{id}>";
-
- internal static ImmutableArray GetUserMentions(string text, IMessageChannel channel, IReadOnlyCollection mentionedUsers)
- where TUser : class, IUser
- {
- var matches = _userRegex.Matches(text);
- var builder = ImmutableArray.CreateBuilder(matches.Count);
- foreach (var match in matches.OfType())
- {
- ulong id;
- if (ulong.TryParse(match.Groups[1].Value, NumberStyles.None, CultureInfo.InvariantCulture, out id))
- {
- TUser user = null;
-
- //Verify this user was actually mentioned
- foreach (var userMention in mentionedUsers)
- {
- if (userMention.Id == id)
- {
- user = channel?.GetUserAsync(id, CacheMode.CacheOnly).GetAwaiter().GetResult() as TUser;
- if (user == null) //User not found, fallback to basic mention info
- user = userMention;
- break;
- }
- }
-
- if (user != null)
- builder.Add(user);
- }
- }
- return builder.ToImmutable();
- }
- internal static ImmutableArray GetChannelMentions(string text, IGuild guild)
- {
- var matches = _channelRegex.Matches(text);
- var builder = ImmutableArray.CreateBuilder(matches.Count);
- foreach (var match in matches.OfType())
- {
- ulong id;
- if (ulong.TryParse(match.Groups[1].Value, NumberStyles.None, CultureInfo.InvariantCulture, out id))
- builder.Add(id);
- }
- return builder.ToImmutable();
- }
- internal static ImmutableArray GetRoleMentions(string text, IGuild guild)
- where TRole : class, IRole
- {
- if (guild == null)
- return ImmutableArray.Create();
-
- var matches = _roleRegex.Matches(text);
- var builder = ImmutableArray.CreateBuilder(matches.Count);
- foreach (var match in matches.OfType())
- {
- ulong id;
- if (ulong.TryParse(match.Groups[1].Value, NumberStyles.None, CultureInfo.InvariantCulture, out id))
- {
- var role = guild.GetRole(id) as TRole;
- if (role != null)
- builder.Add(role);
- }
- }
- return builder.ToImmutable();
- }
-
- internal static string ResolveUserMentions(string text, IMessageChannel channel, IReadOnlyCollection mentions, UserMentionHandling mode)
- {
- if (mode == UserMentionHandling.Ignore) return text;
-
- return _userRegex.Replace(text, new MatchEvaluator(e =>
- {
- ulong id;
- if (ulong.TryParse(e.Groups[1].Value, NumberStyles.None, CultureInfo.InvariantCulture, out id))
- {
- IUser user = null;
- foreach (var mention in mentions)
- {
- if (mention.Id == id)
- {
- user = mention;
- break;
- }
- }
- if (user != null)
- {
- string name = user.Username;
-
- var guildUser = user as IGuildUser;
- if (e.Value[2] == '!')
- {
- if (guildUser != null && guildUser.Nickname != null)
- name = guildUser.Nickname;
- }
-
- switch (mode)
- {
- case UserMentionHandling.Remove:
- default:
- return "";
- case UserMentionHandling.Name:
- return $"@{name}";
- case UserMentionHandling.NameAndDiscriminator:
- return $"@{name}#{user.Discriminator}";
- }
- }
- }
- return e.Value;
- }));
- }
- internal static string ResolveChannelMentions(string text, IGuild guild, ChannelMentionHandling mode)
- {
- if (mode == ChannelMentionHandling.Ignore) return text;
-
- return _channelRegex.Replace(text, new MatchEvaluator(e =>
- {
- ulong id;
- if (ulong.TryParse(e.Groups[1].Value, NumberStyles.None, CultureInfo.InvariantCulture, out id))
- {
- switch (mode)
- {
- case ChannelMentionHandling.Remove:
- return "";
- case ChannelMentionHandling.Name:
- IGuildChannel channel = null;
- channel = guild.GetChannelAsync(id, CacheMode.CacheOnly).GetAwaiter().GetResult();
- if (channel != null)
- return $"#{channel.Name}";
- else
- return $"#deleted-channel";
- }
- }
- return e.Value;
- }));
- }
- internal static string ResolveRoleMentions(string text, IReadOnlyCollection mentions, RoleMentionHandling mode)
- {
- if (mode == RoleMentionHandling.Ignore) return text;
-
- return _roleRegex.Replace(text, new MatchEvaluator(e =>
- {
- ulong id;
- if (ulong.TryParse(e.Groups[1].Value, NumberStyles.None, CultureInfo.InvariantCulture, out id))
- {
- switch (mode)
- {
- case RoleMentionHandling.Remove:
- return "";
- case RoleMentionHandling.Name:
- IRole role = null;
- foreach (var mention in mentions)
- {
- if (mention.Id == id)
- {
- role = mention;
- break;
- }
- }
- if (role != null)
- return $"@{role.Name}";
- else
- return $"@deleted-role";
- }
- }
- return e.Value;
- }));
- }
- internal static string ResolveEveryoneMentions(string text, EveryoneMentionHandling mode)
- {
- if (mode == EveryoneMentionHandling.Ignore) return text;
-
- switch (mode)
- {
- case EveryoneMentionHandling.Sanitize:
- return text.Replace("@everyone", "@\x200beveryone").Replace("@here", "@\x200bhere");
- case EveryoneMentionHandling.Remove:
- default:
- return text.Replace("@everyone", "").Replace("@here", "");
- }
- }
- }
-}
diff --git a/src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs b/src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs
index b1da6c0b5..e21295a92 100644
--- a/src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs
+++ b/src/Discord.Net.Rest/Entities/Messages/RestUserMessage.cs
@@ -102,9 +102,9 @@ namespace Discord.Rest
{
var text = model.Content.Value;
- _mentionedUsers = MentionsHelper.GetUserMentions(text, null, mentions);
- _mentionedChannelIds = MentionsHelper.GetChannelMentions(text, null);
- _mentionedRoles = MentionsHelper.GetRoleMentions(text, null);
+ _mentionedUsers = MentionUtils.GetUserMentions(text, null, mentions);
+ _mentionedChannelIds = MentionUtils.GetChannelMentions(text, null);
+ _mentionedRoles = MentionUtils.GetRoleMentions(text, null);
model.Content = text;
}
}
@@ -128,10 +128,10 @@ namespace Discord.Rest
public string Resolve(string text, UserMentionHandling userHandling, ChannelMentionHandling channelHandling,
RoleMentionHandling roleHandling, EveryoneMentionHandling everyoneHandling)
{
- text = MentionsHelper.ResolveUserMentions(text, null, MentionedUsers, userHandling);
- text = MentionsHelper.ResolveChannelMentions(text, null, channelHandling);
- text = MentionsHelper.ResolveRoleMentions(text, MentionedRoles, roleHandling);
- text = MentionsHelper.ResolveEveryoneMentions(text, everyoneHandling);
+ text = MentionUtils.ResolveUserMentions(text, null, MentionedUsers, userHandling);
+ text = MentionUtils.ResolveChannelMentions(text, null, channelHandling);
+ text = MentionUtils.ResolveRoleMentions(text, MentionedRoles, roleHandling);
+ text = MentionUtils.ResolveEveryoneMentions(text, everyoneHandling);
return text;
}
diff --git a/src/Discord.Net.WebSocket/API/Gateway/RequestMembersParams.cs b/src/Discord.Net.WebSocket/API/Gateway/RequestMembersParams.cs
index a33d1f412..05ec87f56 100644
--- a/src/Discord.Net.WebSocket/API/Gateway/RequestMembersParams.cs
+++ b/src/Discord.Net.WebSocket/API/Gateway/RequestMembersParams.cs
@@ -1,7 +1,6 @@
#pragma warning disable CS1591
using Newtonsoft.Json;
using System.Collections.Generic;
-using System.Linq;
namespace Discord.API.Gateway
{
@@ -14,6 +13,6 @@ namespace Discord.API.Gateway
public int Limit { get; set; }
[JsonProperty("guild_id")]
- private ulong[] GuildIds { get; set; }
+ public IEnumerable GuildIds { get; set; }
}
}
diff --git a/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs b/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs
index 042248152..683f6ec3d 100644
--- a/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs
+++ b/src/Discord.Net.WebSocket/Entities/Messages/SocketUserMessage.cs
@@ -105,9 +105,9 @@ namespace Discord.WebSocket
var text = model.Content.Value;
var guild = (Channel as SocketGuildChannel)?.Guild;
- _mentionedUsers = MentionsHelper.GetUserMentions(text, Channel, mentions);
- _mentionedChannelIds = MentionsHelper.GetChannelMentions(text, guild);
- _mentionedRoles = MentionsHelper.GetRoleMentions(text, guild);
+ _mentionedUsers = MentionUtils.GetUserMentions(text, Channel, mentions);
+ _mentionedChannelIds = MentionUtils.GetChannelMentions(text, guild);
+ _mentionedRoles = MentionUtils.GetRoleMentions(text, guild);
model.Content = text;
}
}
@@ -131,10 +131,10 @@ namespace Discord.WebSocket
public string Resolve(string text, UserMentionHandling userHandling, ChannelMentionHandling channelHandling,
RoleMentionHandling roleHandling, EveryoneMentionHandling everyoneHandling)
{
- text = MentionsHelper.ResolveUserMentions(text, null, MentionedUsers, userHandling);
- text = MentionsHelper.ResolveChannelMentions(text, null, channelHandling);
- text = MentionsHelper.ResolveRoleMentions(text, MentionedRoles, roleHandling);
- text = MentionsHelper.ResolveEveryoneMentions(text, everyoneHandling);
+ text = MentionUtils.ResolveUserMentions(text, null, MentionedUsers, userHandling);
+ text = MentionUtils.ResolveChannelMentions(text, null, channelHandling);
+ text = MentionUtils.ResolveRoleMentions(text, MentionedRoles, roleHandling);
+ text = MentionUtils.ResolveEveryoneMentions(text, everyoneHandling);
return text;
}