Fix Build Errors
This commit is contained in:
parent
23cf06df4c
commit
c99784b9dc
@ -6,12 +6,11 @@ using App.Metrics;
|
||||
|
||||
using Autofac;
|
||||
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
|
||||
using DSharpPlus;
|
||||
using DSharpPlus.Entities;
|
||||
|
||||
using PluralKit.Bot.Utils;
|
||||
using PluralKit.Core;
|
||||
|
||||
namespace PluralKit.Bot
|
||||
@ -20,6 +19,7 @@ namespace PluralKit.Bot
|
||||
{
|
||||
private ILifetimeScope _provider;
|
||||
|
||||
private readonly DiscordRestClient _rest;
|
||||
private readonly DiscordShardedClient _client;
|
||||
private readonly DiscordClient _shard;
|
||||
private readonly DiscordMessage _message;
|
||||
@ -34,6 +34,7 @@ namespace PluralKit.Bot
|
||||
public Context(ILifetimeScope provider, DiscordClient shard, DiscordMessage message, int commandParseOffset,
|
||||
PKSystem senderSystem)
|
||||
{
|
||||
_rest = provider.Resolve<DiscordRestClient>();
|
||||
_client = provider.Resolve<DiscordShardedClient>();
|
||||
_message = message;
|
||||
_shard = shard;
|
||||
@ -50,6 +51,9 @@ namespace PluralKit.Bot
|
||||
public DiscordGuild Guild => _message.Channel.Guild;
|
||||
public DiscordClient Shard => _shard;
|
||||
public DiscordShardedClient Client => _client;
|
||||
|
||||
public DiscordRestClient Rest => _rest;
|
||||
|
||||
public PKSystem System => _senderSystem;
|
||||
|
||||
public string PopArgument() => _parameters.Pop();
|
||||
@ -280,10 +284,11 @@ namespace PluralKit.Bot
|
||||
public DiscordChannel MatchChannel()
|
||||
{
|
||||
if (!MentionUtils.TryParseChannel(PeekArgument(), out var channel)) return null;
|
||||
if (!(_client.GetChannelAsync(channel) is ITextChannel textChannel)) return null;
|
||||
var discordChannel = _rest.GetChannelAsync(channel).GetAwaiter().GetResult();
|
||||
if (discordChannel.Type != ChannelType.Text) return null;
|
||||
|
||||
PopArgument();
|
||||
return textChannel;
|
||||
return null;// return textChannel;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Discord;
|
||||
using DSharpPlus.Entities;
|
||||
|
||||
using PluralKit.Core;
|
||||
|
||||
@ -96,12 +96,12 @@ namespace PluralKit.Bot
|
||||
await ctx.Reply($"{Emojis.Success} Autoproxy set to **{member.Name}** in this server.");
|
||||
}
|
||||
|
||||
private async Task<Embed> CreateAutoproxyStatusEmbed(Context ctx)
|
||||
private async Task<DiscordEmbed> CreateAutoproxyStatusEmbed(Context ctx)
|
||||
{
|
||||
var settings = await _data.GetSystemGuildSettings(ctx.System, ctx.Guild.Id);
|
||||
|
||||
var commandList = "**pk;autoproxy latch** - Autoproxies as last-proxied member\n**pk;autoproxy front** - Autoproxies as current (first) fronter\n**pk;autoproxy <member>** - Autoproxies as a specific member";
|
||||
var eb = new EmbedBuilder().WithTitle($"Current autoproxy status (for {ctx.Guild.Name.EscapeMarkdown()})");
|
||||
var eb = new DiscordEmbedBuilder().WithTitle($"Current autoproxy status (for {ctx.Guild.Name.EscapeMarkdown()})");
|
||||
|
||||
switch (settings.AutoproxyMode) {
|
||||
case AutoproxyMode.Off: eb.WithDescription($"Autoproxy is currently **off** in this server. To enable it, use one of the following commands:\n{commandList}");
|
||||
|
@ -1,7 +1,7 @@
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Discord.WebSocket;
|
||||
using DSharpPlus;
|
||||
|
||||
using PluralKit.Core;
|
||||
|
||||
@ -81,6 +81,7 @@ namespace PluralKit.Bot
|
||||
|
||||
public CommandTree(DiscordShardedClient client)
|
||||
{
|
||||
|
||||
_client = client;
|
||||
}
|
||||
|
||||
@ -345,7 +346,7 @@ namespace PluralKit.Bot
|
||||
{
|
||||
// Try to resolve the user ID to find the associated account,
|
||||
// so we can print their username.
|
||||
var user = await _client.Rest.GetUserAsync(id);
|
||||
var user = await ctx.Rest.GetUserAsync(id);
|
||||
|
||||
// Print descriptive errors based on whether we found the user or not.
|
||||
if (user == null)
|
||||
|
@ -1,6 +1,6 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Discord;
|
||||
using DSharpPlus.Entities;
|
||||
|
||||
using PluralKit.Core;
|
||||
|
||||
@ -10,7 +10,7 @@ namespace PluralKit.Bot
|
||||
{
|
||||
public async Task HelpRoot(Context ctx)
|
||||
{
|
||||
await ctx.Reply(embed: new EmbedBuilder()
|
||||
await ctx.Reply(embed: new DiscordEmbedBuilder()
|
||||
.WithTitle("PluralKit")
|
||||
.WithDescription("PluralKit is a bot designed for plural communities on Discord. It allows you to register systems, maintain system information, set up message proxying, log switches, and more.")
|
||||
.AddField("What is this for? What are systems?", "This bot detects messages with certain tags associated with a profile, then replaces that message under a \"pseudo-account\" of that profile using webhooks. This is useful for multiple people sharing one body (aka \"systems\"), people who wish to roleplay as different characters without having several accounts, or anyone else who may want to post messages as a different person from the same account.")
|
||||
@ -20,7 +20,7 @@ namespace PluralKit.Bot
|
||||
.AddField("More information", "For a full list of commands, see [the command list](https://pluralkit.me/commands).\nFor a more in-depth explanation of message proxying, see [the documentation](https://pluralkit.me/guide#proxying).\nIf you're an existing user of Tupperbox, type `pk;import` and attach a Tupperbox export file (from `tul!export`) to import your data from there.")
|
||||
.AddField("Support server", "We also have a Discord server for support, discussion, suggestions, announcements, etc: https://discord.gg/PczBt78")
|
||||
.WithFooter("By @Ske#6201 | GitHub: https://github.com/xSke/PluralKit/ | Website: https://pluralkit.me/")
|
||||
.WithColor(Color.Blue)
|
||||
.WithColor(DiscordColor.Blue)
|
||||
.Build());
|
||||
}
|
||||
}
|
||||
|
@ -5,10 +5,9 @@ using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Discord;
|
||||
using Discord.Net;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using DSharpPlus.Exceptions;
|
||||
using DSharpPlus.Entities;
|
||||
|
||||
using PluralKit.Core;
|
||||
|
||||
@ -134,13 +133,14 @@ namespace PluralKit.Bot
|
||||
|
||||
try
|
||||
{
|
||||
await ctx.Author.SendFileAsync(stream, "system.json", $"{Emojis.Success} Here you go!");
|
||||
|
||||
var dm = await ctx.Rest.CreateDmAsync(ctx.Author.Id);
|
||||
await dm.SendFileAsync("system.json", stream, $"{Emojis.Success} Here you go!");
|
||||
|
||||
// If the original message wasn't posted in DMs, send a public reminder
|
||||
if (!(ctx.Channel is IDMChannel))
|
||||
if (!(ctx.Channel is DiscordDmChannel))
|
||||
await ctx.Reply($"{Emojis.Success} Check your DMs!");
|
||||
}
|
||||
catch (HttpException)
|
||||
catch (UnauthorizedException)
|
||||
{
|
||||
// If user has DMs closed, tell 'em to open them
|
||||
await ctx.Reply(
|
||||
|
@ -1,7 +1,8 @@
|
||||
using System.Linq;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Discord;
|
||||
using DSharpPlus;
|
||||
using DSharpPlus.Entities;
|
||||
|
||||
using PluralKit.Core;
|
||||
|
||||
@ -39,7 +40,7 @@ namespace PluralKit.Bot
|
||||
{
|
||||
if ((target.AvatarUrl?.Trim() ?? "").Length > 0)
|
||||
{
|
||||
var eb = new EmbedBuilder()
|
||||
var eb = new DiscordEmbedBuilder()
|
||||
.WithTitle($"{target.Name.SanitizeMentions()}'s avatar")
|
||||
.WithImageUrl(target.AvatarUrl);
|
||||
if (target.System == ctx.System?.Id)
|
||||
@ -55,18 +56,17 @@ namespace PluralKit.Bot
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var user = await ctx.MatchUser();
|
||||
if (ctx.System == null) throw Errors.NoSystemError;
|
||||
if (target.System != ctx.System.Id) throw Errors.NotOwnMemberError;
|
||||
|
||||
else if (await ctx.MatchUser() is IUser user)
|
||||
else if (user != null)
|
||||
{
|
||||
if (user.AvatarId == null) throw Errors.UserHasNoAvatar;
|
||||
if (user.AvatarUrl == user.DefaultAvatarUrl) throw Errors.UserHasNoAvatar; //TODO: is this necessary?
|
||||
target.AvatarUrl = user.GetAvatarUrl(ImageFormat.Png, size: 256);
|
||||
|
||||
await _data.SaveMember(target);
|
||||
|
||||
var embed = new EmbedBuilder().WithImageUrl(target.AvatarUrl).Build();
|
||||
var embed = new DiscordEmbedBuilder().WithImageUrl(target.AvatarUrl).Build();
|
||||
await ctx.Reply(
|
||||
$"{Emojis.Success} Member avatar changed to {user.Username}'s avatar! {Emojis.Warn} Please note that if {user.Username} changes their avatar, the member's avatar will need to be re-set.", embed: embed);
|
||||
}
|
||||
@ -76,10 +76,10 @@ namespace PluralKit.Bot
|
||||
target.AvatarUrl = url;
|
||||
await _data.SaveMember(target);
|
||||
|
||||
var embed = new EmbedBuilder().WithImageUrl(url).Build();
|
||||
var embed = new DiscordEmbedBuilder().WithImageUrl(url).Build();
|
||||
await ctx.Reply($"{Emojis.Success} Member avatar changed.", embed: embed);
|
||||
}
|
||||
else if (ctx.Message.Attachments.FirstOrDefault() is Attachment attachment)
|
||||
else if (ctx.Message.Attachments.FirstOrDefault() is DiscordAttachment attachment)
|
||||
{
|
||||
await AvatarUtils.VerifyAvatarOrThrow(attachment.Url);
|
||||
target.AvatarUrl = attachment.Url;
|
||||
@ -113,7 +113,7 @@ namespace PluralKit.Bot
|
||||
{
|
||||
if ((guildData.AvatarUrl?.Trim() ?? "").Length > 0)
|
||||
{
|
||||
var eb = new EmbedBuilder()
|
||||
var eb = new DiscordEmbedBuilder()
|
||||
.WithTitle($"{target.Name.SanitizeMentions()}'s server avatar (for {ctx.Guild.Name})")
|
||||
.WithImageUrl(guildData.AvatarUrl);
|
||||
if (target.System == ctx.System?.Id)
|
||||
@ -125,17 +125,17 @@ namespace PluralKit.Bot
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var user = await ctx.MatchUser();
|
||||
if (ctx.System == null) throw Errors.NoSystemError;
|
||||
if (target.System != ctx.System.Id) throw Errors.NotOwnMemberError;
|
||||
|
||||
if (await ctx.MatchUser() is IUser user)
|
||||
if (user != null)
|
||||
{
|
||||
if (user.AvatarId == null) throw Errors.UserHasNoAvatar;
|
||||
if (user.AvatarUrl == user.DefaultAvatarUrl) throw Errors.UserHasNoAvatar;
|
||||
guildData.AvatarUrl = user.GetAvatarUrl(ImageFormat.Png, size: 256);
|
||||
await _data.SetMemberGuildSettings(target, ctx.Guild.Id, guildData);
|
||||
|
||||
var embed = new EmbedBuilder().WithImageUrl(guildData.AvatarUrl).Build();
|
||||
var embed = new DiscordEmbedBuilder().WithImageUrl(guildData.AvatarUrl).Build();
|
||||
await ctx.Reply(
|
||||
$"{Emojis.Success} Member server avatar changed to {user.Username}'s avatar! This avatar will now be used when proxying in this server (**{ctx.Guild.Name}**). {Emojis.Warn} Please note that if {user.Username} changes their avatar, the member's server avatar will need to be re-set.", embed: embed);
|
||||
}
|
||||
@ -145,10 +145,10 @@ namespace PluralKit.Bot
|
||||
guildData.AvatarUrl = url;
|
||||
await _data.SetMemberGuildSettings(target, ctx.Guild.Id, guildData);
|
||||
|
||||
var embed = new EmbedBuilder().WithImageUrl(url).Build();
|
||||
var embed = new DiscordEmbedBuilder().WithImageUrl(url).Build();
|
||||
await ctx.Reply($"{Emojis.Success} Member server avatar changed. This avatar will now be used when proxying in this server (**{ctx.Guild.Name}**).", embed: embed);
|
||||
}
|
||||
else if (ctx.Message.Attachments.FirstOrDefault() is Attachment attachment)
|
||||
else if (ctx.Message.Attachments.FirstOrDefault() is DiscordAttachment attachment)
|
||||
{
|
||||
await AvatarUtils.VerifyAvatarOrThrow(attachment.Url);
|
||||
guildData.AvatarUrl = attachment.Url;
|
||||
|
@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Discord;
|
||||
using DSharpPlus.Entities;
|
||||
|
||||
using NodaTime;
|
||||
|
||||
@ -86,7 +86,7 @@ namespace PluralKit.Bot
|
||||
else if (ctx.MatchFlag("r", "raw"))
|
||||
await ctx.Reply($"```\n{target.Description.SanitizeMentions()}\n```");
|
||||
else
|
||||
await ctx.Reply(embed: new EmbedBuilder()
|
||||
await ctx.Reply(embed: new DiscordEmbedBuilder()
|
||||
.WithTitle("Member description")
|
||||
.WithDescription(target.Description)
|
||||
.AddField("\u200B", $"To print the description with formatting, type `pk;member {target.Hid} description -raw`."
|
||||
@ -163,7 +163,7 @@ namespace PluralKit.Bot
|
||||
else
|
||||
await ctx.Reply("This member does not have a color set.");
|
||||
else
|
||||
await ctx.Reply(embed: new EmbedBuilder()
|
||||
await ctx.Reply(embed: new DiscordEmbedBuilder()
|
||||
.WithTitle("Member color")
|
||||
.WithColor(target.Color.ToDiscordColor().Value)
|
||||
.WithThumbnailUrl($"https://fakeimg.pl/256x256/{target.Color}/?text=%20")
|
||||
@ -180,7 +180,7 @@ namespace PluralKit.Bot
|
||||
target.Color = color.ToLower();
|
||||
await _data.SaveMember(target);
|
||||
|
||||
await ctx.Reply(embed: new EmbedBuilder()
|
||||
await ctx.Reply(embed: new DiscordEmbedBuilder()
|
||||
.WithTitle($"{Emojis.Success} Member color changed.")
|
||||
.WithColor(target.Color.ToDiscordColor().Value)
|
||||
.WithThumbnailUrl($"https://fakeimg.pl/256x256/{target.Color}/?text=%20")
|
||||
@ -220,13 +220,13 @@ namespace PluralKit.Bot
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<EmbedBuilder> CreateMemberNameInfoEmbed(Context ctx, PKMember target)
|
||||
private async Task<DiscordEmbedBuilder> CreateMemberNameInfoEmbed(Context ctx, PKMember target)
|
||||
{
|
||||
MemberGuildSettings memberGuildConfig = null;
|
||||
if (ctx.Guild != null)
|
||||
memberGuildConfig = await _data.GetMemberGuildSettings(target, ctx.Guild.Id);
|
||||
|
||||
var eb = new EmbedBuilder().WithTitle($"Member names")
|
||||
var eb = new DiscordEmbedBuilder().WithTitle($"Member names")
|
||||
.WithFooter($"Member ID: {target.Hid} | Active name in bold. Server name overrides display name, which overrides base name.");
|
||||
|
||||
if (target.DisplayName == null && memberGuildConfig?.DisplayName == null)
|
||||
|
@ -3,16 +3,18 @@ using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Net.WebSockets;
|
||||
|
||||
using App.Metrics;
|
||||
|
||||
using Discord;
|
||||
using DSharpPlus;
|
||||
|
||||
using Humanizer;
|
||||
|
||||
using NodaTime;
|
||||
|
||||
using PluralKit.Core;
|
||||
using DSharpPlus.Entities;
|
||||
|
||||
namespace PluralKit.Bot {
|
||||
public class Misc
|
||||
@ -36,18 +38,16 @@ namespace PluralKit.Bot {
|
||||
|
||||
public async Task Invite(Context ctx)
|
||||
{
|
||||
var clientId = _botConfig.ClientId ?? (await ctx.Client.GetApplicationInfoAsync()).Id;
|
||||
var permissions = new GuildPermissions(
|
||||
addReactions: true,
|
||||
attachFiles: true,
|
||||
embedLinks: true,
|
||||
manageMessages: true,
|
||||
manageWebhooks: true,
|
||||
readMessageHistory: true,
|
||||
sendMessages: true
|
||||
);
|
||||
|
||||
var invite = $"https://discordapp.com/oauth2/authorize?client_id={clientId}&scope=bot&permissions={permissions.RawValue}";
|
||||
var clientId = _botConfig.ClientId ?? ctx.Client.CurrentApplication.Id;
|
||||
var permissions = new Permissions()
|
||||
.Grant(Permissions.AddReactions)
|
||||
.Grant(Permissions.AttachFiles)
|
||||
.Grant(Permissions.EmbedLinks)
|
||||
.Grant(Permissions.ManageMessages)
|
||||
.Grant(Permissions.ManageWebhooks)
|
||||
.Grant(Permissions.ReadMessageHistory)
|
||||
.Grant(Permissions.SendMessages);
|
||||
var invite = $"https://discordapp.com/oauth2/authorize?client_id={clientId}&scope=bot&permissions={(long)permissions}";
|
||||
await ctx.Reply($"{Emojis.Success} Use this link to add PluralKit to your server:\n<{invite}>");
|
||||
}
|
||||
|
||||
@ -65,8 +65,8 @@ namespace PluralKit.Bot {
|
||||
var totalMessages = _metrics.Snapshot.GetForContext("Application").Gauges.First(m => m.MultidimensionalName == CoreMetrics.MessageCount.Name).Value;
|
||||
|
||||
var shardId = ctx.Shard.ShardId;
|
||||
var shardTotal = ctx.Client.Shards.Count;
|
||||
var shardUpTotal = ctx.Client.Shards.Select(s => s.ConnectionState == ConnectionState.Connected).Count();
|
||||
var shardTotal = ctx.Client.ShardClients.Count;
|
||||
var shardUpTotal = ctx.Client.ShardClients.Where(x => x.Value.IsConnected()).Count();
|
||||
var shardInfo = _shards.GetShardInfo(ctx.Shard);
|
||||
|
||||
var process = Process.GetCurrentProcess();
|
||||
@ -74,7 +74,7 @@ namespace PluralKit.Bot {
|
||||
|
||||
var shardUptime = SystemClock.Instance.GetCurrentInstant() - shardInfo.LastConnectionTime;
|
||||
|
||||
var embed = new EmbedBuilder()
|
||||
var embed = new DiscordEmbedBuilder()
|
||||
.AddField("Messages processed", $"{messagesReceived.OneMinuteRate * 60:F1}/m ({messagesReceived.FifteenMinuteRate * 60:F1}/m over 15m)", true)
|
||||
.AddField("Messages proxied", $"{messagesProxied.OneMinuteRate * 60:F1}/m ({messagesProxied.FifteenMinuteRate * 60:F1}/m over 15m)", true)
|
||||
.AddField("Commands executed", $"{commandsRun.OneMinuteRate * 60:F1}/m ({commandsRun.FifteenMinuteRate * 60:F1}/m over 15m)", true)
|
||||
@ -84,17 +84,12 @@ namespace PluralKit.Bot {
|
||||
.AddField("Memory usage", $"{memoryUsage / 1024 / 1024} MiB", true)
|
||||
.AddField("Latency", $"API: {(msg.Timestamp - ctx.Message.Timestamp).TotalMilliseconds:F0} ms, shard: {shardInfo.ShardLatency} ms", true)
|
||||
.AddField("Total numbers", $"{totalSystems:N0} systems, {totalMembers:N0} members, {totalSwitches:N0} switches, {totalMessages:N0} messages");
|
||||
|
||||
await msg.ModifyAsync(f =>
|
||||
{
|
||||
f.Content = "";
|
||||
f.Embed = embed.Build();
|
||||
});
|
||||
await msg.ModifyAsync("", embed.Build());
|
||||
}
|
||||
|
||||
|
||||
public async Task PermCheckGuild(Context ctx)
|
||||
{
|
||||
IGuild guild;
|
||||
DiscordGuild guild;
|
||||
|
||||
if (ctx.Guild != null && !ctx.HasNext())
|
||||
{
|
||||
@ -107,51 +102,52 @@ namespace PluralKit.Bot {
|
||||
throw new PKSyntaxError($"Could not parse `{guildIdStr.SanitizeMentions()}` as an ID.");
|
||||
|
||||
// TODO: will this call break for sharding if you try to request a guild on a different bot instance?
|
||||
guild = ctx.Client.GetGuild(guildId);
|
||||
guild = await ctx.Rest.GetGuildAsync(guildId);
|
||||
if (guild == null)
|
||||
throw Errors.GuildNotFound(guildId);
|
||||
}
|
||||
|
||||
|
||||
var requiredPermissions = new []
|
||||
{
|
||||
ChannelPermission.ViewChannel,
|
||||
ChannelPermission.SendMessages,
|
||||
ChannelPermission.AddReactions,
|
||||
ChannelPermission.AttachFiles,
|
||||
ChannelPermission.EmbedLinks,
|
||||
ChannelPermission.ManageMessages,
|
||||
ChannelPermission.ManageWebhooks
|
||||
Permissions.AccessChannels,
|
||||
Permissions.SendMessages,
|
||||
Permissions.AddReactions,
|
||||
Permissions.AttachFiles,
|
||||
Permissions.EmbedLinks,
|
||||
Permissions.ManageMessages,
|
||||
Permissions.ManageWebhooks
|
||||
};
|
||||
|
||||
// Loop through every channel and group them by sets of permissions missing
|
||||
var permissionsMissing = new Dictionary<ulong, List<ITextChannel>>();
|
||||
foreach (var channel in await guild.GetTextChannelsAsync())
|
||||
var permissionsMissing = new Dictionary<ulong, List<DiscordChannel>>();
|
||||
var guildTextChannels = (await guild.GetChannelsAsync()).Where(x => x.Type == ChannelType.Text);
|
||||
foreach (var channel in guildTextChannels)
|
||||
{
|
||||
// TODO: do we need to hide channels here to prevent info-leaking?
|
||||
var perms = channel.PermissionsIn();
|
||||
var perms = await channel.PermissionsIn(ctx.Client.CurrentUser);
|
||||
|
||||
// We use a bitfield so we can set individual permission bits in the loop
|
||||
ulong missingPermissionField = 0;
|
||||
foreach (var requiredPermission in requiredPermissions)
|
||||
if (!perms.Has(requiredPermission))
|
||||
if (!perms.HasPermission(requiredPermission))
|
||||
missingPermissionField |= (ulong) requiredPermission;
|
||||
|
||||
// If we're not missing any permissions, don't bother adding it to the dict
|
||||
// This means we can check if the dict is empty to see if all channels are proxyable
|
||||
if (missingPermissionField != 0)
|
||||
{
|
||||
permissionsMissing.TryAdd(missingPermissionField, new List<ITextChannel>());
|
||||
permissionsMissing.TryAdd(missingPermissionField, new List<DiscordChannel>());
|
||||
permissionsMissing[missingPermissionField].Add(channel);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the output embed
|
||||
var eb = new EmbedBuilder()
|
||||
var eb = new DiscordEmbedBuilder()
|
||||
.WithTitle($"Permission check for **{guild.Name.SanitizeMentions()}**");
|
||||
|
||||
if (permissionsMissing.Count == 0)
|
||||
{
|
||||
eb.WithDescription($"No errors found, all channels proxyable :)").WithColor(Color.Green);
|
||||
eb.WithDescription($"No errors found, all channels proxyable :)").WithColor(DiscordColor.Green);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -159,15 +155,13 @@ namespace PluralKit.Bot {
|
||||
{
|
||||
// Each missing permission field can have multiple missing channels
|
||||
// so we extract them all and generate a comma-separated list
|
||||
var missingPermissionNames = string.Join(", ", new ChannelPermissions(missingPermissionField)
|
||||
.ToList()
|
||||
.Select(perm => perm.Humanize().Transform(To.TitleCase)));
|
||||
var missingPermissionNames = ((Permissions)missingPermissionField).ToPermissionString();
|
||||
|
||||
var channelsList = string.Join("\n", channels
|
||||
.OrderBy(c => c.Position)
|
||||
.Select(c => $"#{c.Name}"));
|
||||
eb.AddField($"Missing *{missingPermissionNames}*", channelsList.Truncate(1000));
|
||||
eb.WithColor(Color.Red);
|
||||
eb.WithColor(DiscordColor.Red);
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,7 +183,7 @@ namespace PluralKit.Bot {
|
||||
var message = await _data.GetMessage(messageId);
|
||||
if (message == null) throw Errors.MessageNotFound(messageId);
|
||||
|
||||
await ctx.Reply(embed: await _embeds.CreateMessageInfoEmbed(message));
|
||||
await ctx.Reply(embed: await _embeds.CreateMessageInfoEmbed(ctx.Shard, message)); //TODO: test this
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,8 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Discord;
|
||||
using DSharpPlus;
|
||||
using DSharpPlus.Entities;
|
||||
|
||||
using PluralKit.Core;
|
||||
|
||||
@ -20,12 +21,13 @@ namespace PluralKit.Bot
|
||||
|
||||
public async Task SetLogChannel(Context ctx)
|
||||
{
|
||||
ctx.CheckGuildContext().CheckAuthorPermission(GuildPermission.ManageGuild, "Manage Server");
|
||||
ctx.CheckGuildContext().CheckAuthorPermission(Permissions.ManageGuild, "Manage Server");
|
||||
|
||||
ITextChannel channel = null;
|
||||
DiscordChannel channel = null;
|
||||
if (ctx.HasNext())
|
||||
channel = ctx.MatchChannel() ?? throw new PKSyntaxError("You must pass a #channel to set.");
|
||||
if (channel != null && channel.GuildId != ctx.Guild.Id) throw new PKError("That channel is not in this server!");
|
||||
if (channel != null && channel.GuildId != ctx.Guild.Id) throw new PKError("That channel is not in this server!");
|
||||
if (channel.Type != ChannelType.Text) throw new PKError("The logging channel must be a text channel."); //TODO: test this
|
||||
|
||||
var cfg = await _data.GetOrCreateGuildConfig(ctx.Guild.Id);
|
||||
cfg.LogChannel = channel?.Id;
|
||||
@ -39,15 +41,16 @@ namespace PluralKit.Bot
|
||||
|
||||
public async Task SetLogEnabled(Context ctx, bool enable)
|
||||
{
|
||||
ctx.CheckGuildContext().CheckAuthorPermission(GuildPermission.ManageGuild, "Manage Server");
|
||||
ctx.CheckGuildContext().CheckAuthorPermission(Permissions.ManageGuild, "Manage Server");
|
||||
|
||||
var affectedChannels = new List<ITextChannel>();
|
||||
var affectedChannels = new List<DiscordChannel>();
|
||||
if (ctx.Match("all"))
|
||||
affectedChannels = (await ctx.Guild.GetChannelsAsync()).OfType<ITextChannel>().ToList();
|
||||
affectedChannels = (await ctx.Guild.GetChannelsAsync()).Where(x => x.Type == ChannelType.Text).ToList();
|
||||
else if (!ctx.HasNext()) throw new PKSyntaxError("You must pass one or more #channels.");
|
||||
else while (ctx.HasNext())
|
||||
{
|
||||
if (!(ctx.MatchChannel() is ITextChannel channel))
|
||||
var channel = ctx.MatchChannel(); //TODO: test this
|
||||
if (channel.Type != ChannelType.Text)
|
||||
throw new PKSyntaxError($"Channel \"{ctx.PopArgument().SanitizeMentions()}\" not found.");
|
||||
if (channel.GuildId != ctx.Guild.Id) throw new PKError($"Channel {ctx.Guild.Id} is not in this server.");
|
||||
affectedChannels.Add(channel);
|
||||
@ -65,15 +68,16 @@ namespace PluralKit.Bot
|
||||
|
||||
public async Task SetBlacklisted(Context ctx, bool onBlacklist)
|
||||
{
|
||||
ctx.CheckGuildContext().CheckAuthorPermission(GuildPermission.ManageGuild, "Manage Server");
|
||||
ctx.CheckGuildContext().CheckAuthorPermission(Permissions.ManageGuild, "Manage Server");
|
||||
|
||||
var affectedChannels = new List<ITextChannel>();
|
||||
var affectedChannels = new List<DiscordChannel>();
|
||||
if (ctx.Match("all"))
|
||||
affectedChannels = (await ctx.Guild.GetChannelsAsync()).OfType<ITextChannel>().ToList();
|
||||
affectedChannels = (await ctx.Guild.GetChannelsAsync()).Where(x => x.Type == ChannelType.Text).ToList();
|
||||
else if (!ctx.HasNext()) throw new PKSyntaxError("You must pass one or more #channels.");
|
||||
else while (ctx.HasNext())
|
||||
{
|
||||
if (!(ctx.MatchChannel() is ITextChannel channel))
|
||||
var channel = ctx.MatchChannel(); //TODO: test this
|
||||
if (channel.Type != ChannelType.Text)
|
||||
throw new PKSyntaxError($"Channel \"{ctx.PopArgument().SanitizeMentions()}\" not found.");
|
||||
if (channel.GuildId != ctx.Guild.Id) throw new PKError($"Channel {ctx.Guild.Id} is not in this server.");
|
||||
affectedChannels.Add(channel);
|
||||
@ -89,7 +93,7 @@ namespace PluralKit.Bot
|
||||
|
||||
public async Task SetLogCleanup(Context ctx)
|
||||
{
|
||||
ctx.CheckGuildContext().CheckAuthorPermission(GuildPermission.ManageGuild, "Manage Server");
|
||||
ctx.CheckGuildContext().CheckAuthorPermission(Permissions.ManageGuild, "Manage Server");
|
||||
|
||||
var guildCfg = await _data.GetOrCreateGuildConfig(ctx.Guild.Id);
|
||||
var botList = string.Join(", ", _cleanService.Bots.Select(b => b.Name).OrderBy(x => x.ToLowerInvariant()));
|
||||
@ -108,7 +112,7 @@ namespace PluralKit.Bot
|
||||
}
|
||||
else
|
||||
{
|
||||
var eb = new EmbedBuilder()
|
||||
var eb = new DiscordEmbedBuilder()
|
||||
.WithTitle("Log cleanup settings")
|
||||
.AddField("Supported bots", botList);
|
||||
|
||||
|
@ -2,7 +2,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Discord;
|
||||
using DSharpPlus.Entities;
|
||||
|
||||
using NodaTime;
|
||||
using NodaTime.TimeZones;
|
||||
@ -140,7 +140,7 @@ namespace PluralKit.Bot
|
||||
var lastSwitchMemberStr = string.Join(", ", await lastSwitchMembers.Select(m => m.Name).ToListAsync());
|
||||
var lastSwitchDeltaStr = DateTimeFormats.DurationFormat.Format(SystemClock.Instance.GetCurrentInstant() - lastTwoSwitches[0].Timestamp);
|
||||
|
||||
IUserMessage msg;
|
||||
DiscordMessage msg;
|
||||
if (lastTwoSwitches.Count == 1)
|
||||
{
|
||||
msg = await ctx.Reply(
|
||||
|
@ -18,9 +18,9 @@ namespace PluralKit.Bot
|
||||
public async Task Query(Context ctx, PKSystem system) {
|
||||
if (system == null) throw Errors.NoSystemError;
|
||||
|
||||
await ctx.Reply(embed: await _embeds.CreateSystemEmbed(system, ctx.LookupContextFor(system)));
|
||||
await ctx.Reply(embed: await _embeds.CreateSystemEmbed(ctx.Shard, system, ctx.LookupContextFor(system)));
|
||||
}
|
||||
|
||||
|
||||
public async Task New(Context ctx)
|
||||
{
|
||||
ctx.CheckNoSystem();
|
||||
|
@ -1,8 +1,9 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Discord;
|
||||
using DSharpPlus;
|
||||
using DSharpPlus.Entities;
|
||||
|
||||
using NodaTime;
|
||||
using NodaTime.Text;
|
||||
@ -70,7 +71,7 @@ namespace PluralKit.Bot
|
||||
else if (ctx.MatchFlag("r", "raw"))
|
||||
await ctx.Reply($"```\n{ctx.System.Description.SanitizeMentions()}\n```");
|
||||
else
|
||||
await ctx.Reply(embed: new EmbedBuilder()
|
||||
await ctx.Reply(embed: new DiscordEmbedBuilder()
|
||||
.WithTitle("System description")
|
||||
.WithDescription(ctx.System.Description)
|
||||
.WithFooter("To print the description with formatting, type `pk;s description -raw`. To clear it, type `pk;s description -clear`. To change it, type `pk;s description <new description>`.")
|
||||
@ -128,7 +129,7 @@ namespace PluralKit.Bot
|
||||
{
|
||||
if ((ctx.System.AvatarUrl?.Trim() ?? "").Length > 0)
|
||||
{
|
||||
var eb = new EmbedBuilder()
|
||||
var eb = new DiscordEmbedBuilder()
|
||||
.WithTitle($"System avatar")
|
||||
.WithImageUrl(ctx.System.AvatarUrl)
|
||||
.WithDescription($"To clear, use `pk;system avatar clear`.");
|
||||
@ -143,11 +144,11 @@ namespace PluralKit.Bot
|
||||
var member = await ctx.MatchUser();
|
||||
if (member != null)
|
||||
{
|
||||
if (member.AvatarId == null) throw Errors.UserHasNoAvatar;
|
||||
if (member.AvatarUrl == member.DefaultAvatarUrl) throw Errors.UserHasNoAvatar;
|
||||
ctx.System.AvatarUrl = member.GetAvatarUrl(ImageFormat.Png, size: 256);
|
||||
await _data.SaveSystem(ctx.System);
|
||||
|
||||
var embed = new EmbedBuilder().WithImageUrl(ctx.System.AvatarUrl).Build();
|
||||
var embed = new DiscordEmbedBuilder().WithImageUrl(ctx.System.AvatarUrl).Build();
|
||||
await ctx.Reply(
|
||||
$"{Emojis.Success} System avatar changed to {member.Username}'s avatar! {Emojis.Warn} Please note that if {member.Username} changes their avatar, the system's avatar will need to be re-set.", embed: embed);
|
||||
}
|
||||
@ -160,7 +161,7 @@ namespace PluralKit.Bot
|
||||
ctx.System.AvatarUrl = url;
|
||||
await _data.SaveSystem(ctx.System);
|
||||
|
||||
var embed = url != null ? new EmbedBuilder().WithImageUrl(url).Build() : null;
|
||||
var embed = url != null ? new DiscordEmbedBuilder().WithImageUrl(url).Build() : null;
|
||||
await ctx.Reply($"{Emojis.Success} System avatar changed.", embed: embed);
|
||||
}
|
||||
}
|
||||
@ -249,7 +250,7 @@ namespace PluralKit.Bot
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(level), level, null)
|
||||
};
|
||||
|
||||
var eb = new EmbedBuilder()
|
||||
var eb = new DiscordEmbedBuilder()
|
||||
.WithTitle("Current privacy settings for your system")
|
||||
.AddField("Description", PrivacyLevelString(ctx.System.DescriptionPrivacy))
|
||||
.AddField("Member list", PrivacyLevelString(ctx.System.MemberListPrivacy))
|
||||
|
@ -1,7 +1,8 @@
|
||||
using System.Linq;
|
||||
using ArgumentException = System.ArgumentException;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Discord;
|
||||
using DSharpPlus.Entities;
|
||||
|
||||
using NodaTime;
|
||||
|
||||
@ -88,9 +89,14 @@ namespace PluralKit.Bot
|
||||
stringToAdd =
|
||||
$"**{membersStr}** ({DateTimeFormats.ZonedDateTimeFormat.Format(sw.Timestamp.InZone(system.Zone))}, {DateTimeFormats.DurationFormat.Format(switchSince)} ago)\n";
|
||||
}
|
||||
|
||||
if (outputStr.Length + stringToAdd.Length > EmbedBuilder.MaxDescriptionLength) break;
|
||||
outputStr += stringToAdd;
|
||||
try // Unfortunately the only way to test DiscordEmbedBuilder.Description max length is this
|
||||
{
|
||||
builder.Description += stringToAdd;
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
break;
|
||||
}// TODO: Make sure this works
|
||||
}
|
||||
|
||||
builder.Description = outputStr;
|
||||
|
@ -1,9 +1,9 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Discord;
|
||||
using DSharpPlus.Entities;
|
||||
|
||||
using Humanizer;
|
||||
|
||||
@ -21,7 +21,7 @@ namespace PluralKit.Bot
|
||||
}
|
||||
|
||||
private async Task RenderMemberList(Context ctx, PKSystem system, bool canShowPrivate, int membersPerPage, string embedTitle, Func<PKMember, bool> filter,
|
||||
Func<EmbedBuilder, IEnumerable<PKMember>, Task>
|
||||
Func<DiscordEmbedBuilder, IEnumerable<PKMember>, Task>
|
||||
renderer)
|
||||
{
|
||||
var authCtx = ctx.LookupContextFor(system);
|
||||
@ -54,7 +54,7 @@ namespace PluralKit.Bot
|
||||
});
|
||||
}
|
||||
|
||||
private Task ShortRenderer(EmbedBuilder eb, IEnumerable<PKMember> members)
|
||||
private Task ShortRenderer(DiscordEmbedBuilder eb, IEnumerable<PKMember> members)
|
||||
{
|
||||
eb.Description = string.Join("\n", members.Select((m) =>
|
||||
{
|
||||
@ -73,7 +73,7 @@ namespace PluralKit.Bot
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private Task LongRenderer(EmbedBuilder eb, IEnumerable<PKMember> members)
|
||||
private Task LongRenderer(DiscordEmbedBuilder eb, IEnumerable<PKMember> members)
|
||||
{
|
||||
foreach (var m in members)
|
||||
{
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Discord;
|
||||
using DSharpPlus;
|
||||
using DSharpPlus.Entities;
|
||||
|
||||
using PluralKit.Core;
|
||||
|
||||
@ -22,14 +23,15 @@ namespace PluralKit.Bot
|
||||
var token = ctx.System.Token ?? await MakeAndSetNewToken(ctx.System);
|
||||
|
||||
// If we're not already in a DM, reply with a reminder to check
|
||||
if (!(ctx.Channel is IDMChannel))
|
||||
if (!(ctx.Channel is DiscordDmChannel))
|
||||
{
|
||||
await ctx.Reply($"{Emojis.Success} Check your DMs!");
|
||||
}
|
||||
|
||||
// DM the user a security disclaimer, and then the token in a separate message (for easy copying on mobile)
|
||||
await ctx.Author.SendMessageAsync($"{Emojis.Warn} Please note that this grants access to modify (and delete!) all your system data, so keep it safe and secure. If it leaks or you need a new one, you can invalidate this one with `pk;token refresh`.\n\nYour token is below:");
|
||||
await ctx.Author.SendMessageAsync(token);
|
||||
var dm = await ctx.Rest.CreateDmAsync(ctx.Author.Id);
|
||||
await dm.SendMessageAsync($"{Emojis.Warn} Please note that this grants access to modify (and delete!) all your system data, so keep it safe and secure. If it leaks or you need a new one, you can invalidate this one with `pk;token refresh`.\n\nYour token is below:");
|
||||
await dm.SendMessageAsync(token);
|
||||
}
|
||||
|
||||
private async Task<string> MakeAndSetNewToken(PKSystem system)
|
||||
@ -55,14 +57,15 @@ namespace PluralKit.Bot
|
||||
var token = await MakeAndSetNewToken(ctx.System);
|
||||
|
||||
// If we're not already in a DM, reply with a reminder to check
|
||||
if (!(ctx.Channel is IDMChannel))
|
||||
if (!(ctx.Channel is DiscordDmChannel))
|
||||
{
|
||||
await ctx.Reply($"{Emojis.Success} Check your DMs!");
|
||||
}
|
||||
|
||||
|
||||
// DM the user an invalidation disclaimer, and then the token in a separate message (for easy copying on mobile)
|
||||
await ctx.Author.SendMessageAsync($"{Emojis.Warn} Your previous API token has been invalidated. You will need to change it anywhere it's currently used.\n\nYour token is below:");
|
||||
await ctx.Author.SendMessageAsync(token);
|
||||
var dm = await ctx.Rest.CreateDmAsync(ctx.Author.Id);
|
||||
await dm.SendMessageAsync($"{Emojis.Warn} Your previous API token has been invalidated. You will need to change it anywhere it's currently used.\n\nYour token is below:");
|
||||
await dm.SendMessageAsync(token);
|
||||
}
|
||||
}
|
||||
}
|
23
PluralKit.Bot/Extensions.cs
Normal file
23
PluralKit.Bot/Extensions.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using DSharpPlus;
|
||||
|
||||
using System.Net.WebSockets;
|
||||
|
||||
namespace PluralKit.Bot
|
||||
{
|
||||
static class Extensions
|
||||
{
|
||||
//Unfortunately D#+ doesn't expose the connection state of the client, so we have to test for it instead
|
||||
public static bool IsConnected(this DiscordClient client)
|
||||
{
|
||||
try
|
||||
{
|
||||
client.GetConnectionsAsync().GetAwaiter().GetResult();
|
||||
}
|
||||
catch(WebSocketException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -15,14 +15,20 @@ namespace PluralKit.Bot
|
||||
{
|
||||
protected override void Load(ContainerBuilder builder)
|
||||
{
|
||||
// Client
|
||||
// Clients
|
||||
builder.Register(c => new DiscordShardedClient(new DiscordConfiguration
|
||||
{
|
||||
Token = c.Resolve<BotConfig>().Token,
|
||||
TokenType = TokenType.Bot,
|
||||
MessageCacheSize = 0,
|
||||
})).AsSelf().SingleInstance();
|
||||
|
||||
builder.Register(c => new DiscordRestClient(new DiscordConfiguration
|
||||
{
|
||||
Token = c.Resolve<BotConfig>().Token,
|
||||
TokenType = TokenType.Bot,
|
||||
MessageCacheSize = 0,
|
||||
})).AsSelf().SingleInstance();
|
||||
|
||||
// Commands
|
||||
builder.RegisterType<CommandTree>().AsSelf();
|
||||
builder.RegisterType<Autoproxy>().AsSelf();
|
||||
|
@ -10,7 +10,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DSharpPlus" Version="4.0.0-nightly-00684" />
|
||||
<PackageReference Include="DSharpPlus" Version="4.0.0-nightly-00686" />
|
||||
<PackageReference Include="DSharpPlus.Rest" Version="4.0.0-nightly-00686" />
|
||||
<PackageReference Include="Humanizer.Core" Version="2.7.9" />
|
||||
<PackageReference Include="Sentry" Version="2.0.0-beta7" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.0-beta0007" />
|
||||
|
121
PluralKit.Bot/Utils/MentionUtils.cs
Normal file
121
PluralKit.Bot/Utils/MentionUtils.cs
Normal file
@ -0,0 +1,121 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace PluralKit.Bot.Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a series of helper methods for parsing mentions.
|
||||
/// </summary>
|
||||
public static class MentionUtils
|
||||
{
|
||||
private const char SanitizeChar = '\x200b';
|
||||
|
||||
//If the system can't be positive a user doesn't have a nickname, assume useNickname = true (source: Jake)
|
||||
internal static string MentionUser(string id, bool useNickname = true) => useNickname ? $"<@!{id}>" : $"<@{id}>";
|
||||
/// <summary>
|
||||
/// Returns a mention string based on the user ID.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A user mention string (e.g. <@80351110224678912>).
|
||||
/// </returns>
|
||||
public static string MentionUser(ulong id) => MentionUser(id.ToString(), true);
|
||||
internal static string MentionChannel(string id) => $"<#{id}>";
|
||||
/// <summary>
|
||||
/// Returns a mention string based on the channel ID.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A channel mention string (e.g. <#103735883630395392>).
|
||||
/// </returns>
|
||||
public static string MentionChannel(ulong id) => MentionChannel(id.ToString());
|
||||
internal static string MentionRole(string id) => $"<@&{id}>";
|
||||
/// <summary>
|
||||
/// Returns a mention string based on the role ID.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A role mention string (e.g. <@&165511591545143296>).
|
||||
/// </returns>
|
||||
public static string MentionRole(ulong id) => MentionRole(id.ToString());
|
||||
|
||||
/// <summary>
|
||||
/// Parses a provided user mention string.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentException">Invalid mention format.</exception>
|
||||
public static ulong ParseUser(string text)
|
||||
{
|
||||
if (TryParseUser(text, out ulong id))
|
||||
return id;
|
||||
throw new ArgumentException(message: "Invalid mention format.", paramName: nameof(text));
|
||||
}
|
||||
/// <summary>
|
||||
/// Tries to parse a provided user mention string.
|
||||
/// </summary>
|
||||
public static bool TryParseUser(string text, out ulong userId)
|
||||
{
|
||||
if (text.Length >= 3 && text[0] == '<' && text[1] == '@' && text[text.Length - 1] == '>')
|
||||
{
|
||||
if (text.Length >= 4 && text[2] == '!')
|
||||
text = text.Substring(3, text.Length - 4); //<@!123>
|
||||
else
|
||||
text = text.Substring(2, text.Length - 3); //<@123>
|
||||
|
||||
if (ulong.TryParse(text, NumberStyles.None, CultureInfo.InvariantCulture, out userId))
|
||||
return true;
|
||||
}
|
||||
userId = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses a provided channel mention string.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentException">Invalid mention format.</exception>
|
||||
public static ulong ParseChannel(string text)
|
||||
{
|
||||
if (TryParseChannel(text, out ulong id))
|
||||
return id;
|
||||
throw new ArgumentException(message: "Invalid mention format.", paramName: nameof(text));
|
||||
}
|
||||
/// <summary>
|
||||
/// Tries to parse a provided channel mention string.
|
||||
/// </summary>
|
||||
public static bool TryParseChannel(string text, out ulong channelId)
|
||||
{
|
||||
if (text.Length >= 3 && text[0] == '<' && text[1] == '#' && text[text.Length - 1] == '>')
|
||||
{
|
||||
text = text.Substring(2, text.Length - 3); //<#123>
|
||||
|
||||
if (ulong.TryParse(text, NumberStyles.None, CultureInfo.InvariantCulture, out channelId))
|
||||
return true;
|
||||
}
|
||||
channelId = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses a provided role mention string.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentException">Invalid mention format.</exception>
|
||||
public static ulong ParseRole(string text)
|
||||
{
|
||||
if (TryParseRole(text, out ulong id))
|
||||
return id;
|
||||
throw new ArgumentException(message: "Invalid mention format.", paramName: nameof(text));
|
||||
}
|
||||
/// <summary>
|
||||
/// Tries to parse a provided role mention string.
|
||||
/// </summary>
|
||||
public static bool TryParseRole(string text, out ulong roleId)
|
||||
{
|
||||
if (text.Length >= 4 && text[0] == '<' && text[1] == '@' && text[2] == '&' && text[text.Length - 1] == '>')
|
||||
{
|
||||
text = text.Substring(3, text.Length - 4); //<@&123>
|
||||
|
||||
if (ulong.TryParse(text, NumberStyles.None, CultureInfo.InvariantCulture, out roleId))
|
||||
return true;
|
||||
}
|
||||
roleId = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user