feat: respect Discord permissions in pk;message and pk;edit
This commit is contained in:
		@@ -1,7 +1,9 @@
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
using Autofac;
 | 
			
		||||
 | 
			
		||||
using Myriad.Extensions;
 | 
			
		||||
using Myriad.Types;
 | 
			
		||||
 | 
			
		||||
using PluralKit.Core;
 | 
			
		||||
@@ -57,6 +59,28 @@ namespace PluralKit.Bot
 | 
			
		||||
            return ctx;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static async Task<bool> CheckPermissionsInGuildChannel(this Context ctx, Channel channel, PermissionSet neededPerms)
 | 
			
		||||
        {
 | 
			
		||||
            var guild = ctx.Cache.GetGuild(channel.GuildId.Value);
 | 
			
		||||
            if (guild == null)
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            var guildMember = ctx.Member;
 | 
			
		||||
 | 
			
		||||
            if (ctx.Guild?.Id != channel.GuildId)
 | 
			
		||||
            {
 | 
			
		||||
                guildMember = await ctx.Rest.GetGuildMember(channel.GuildId.Value, ctx.Author.Id);
 | 
			
		||||
                if (guildMember == null)
 | 
			
		||||
                    return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var userPermissions = PermissionExtensions.PermissionsFor(guild, channel, ctx.Author.Id, guildMember);
 | 
			
		||||
            if ((userPermissions & neededPerms) == 0)
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static bool CheckBotAdmin(this Context ctx)
 | 
			
		||||
        {
 | 
			
		||||
            var botConfig = ctx.Services.Resolve<BotConfig>();
 | 
			
		||||
 
 | 
			
		||||
@@ -169,29 +169,15 @@ namespace PluralKit.Bot
 | 
			
		||||
                throw new PKSyntaxError("You need to specify a channel.");
 | 
			
		||||
 | 
			
		||||
            var error = "Channel not found or you do not have permissions to access it.";
 | 
			
		||||
 | 
			
		||||
            var channel = await ctx.MatchChannel();
 | 
			
		||||
            if (channel == null || channel.GuildId == null)
 | 
			
		||||
                throw new PKError(error);
 | 
			
		||||
 | 
			
		||||
            var guild = _cache.GetGuild(channel.GuildId.Value);
 | 
			
		||||
            if (guild == null)
 | 
			
		||||
            if (!await ctx.CheckPermissionsInGuildChannel(channel, PermissionSet.ViewChannel))
 | 
			
		||||
                throw new PKError(error);
 | 
			
		||||
 | 
			
		||||
            var guildMember = await _rest.GetGuildMember(channel.GuildId.Value, ctx.Author.Id);
 | 
			
		||||
            if (guildMember == null)
 | 
			
		||||
                throw new PKError(error);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            var botPermissions = _bot.PermissionsIn(channel.Id);
 | 
			
		||||
            var webhookPermissions = _cache.EveryonePermissions(channel);
 | 
			
		||||
            var userPermissions = PermissionExtensions.PermissionsFor(guild, channel, ctx.Author.Id, guildMember);
 | 
			
		||||
 | 
			
		||||
            if ((userPermissions & PermissionSet.ViewChannel) == 0)
 | 
			
		||||
                throw new PKError(error);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            // We use a bitfield so we can set individual permission bits
 | 
			
		||||
            ulong missingPermissions = 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -105,6 +105,20 @@ namespace PluralKit.Bot
 | 
			
		||||
                    throw new PKError("Could not find a recent message to edit.");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (msg.Message.Channel != ctx.Channel.Id)
 | 
			
		||||
            {
 | 
			
		||||
                var error = "The channel where the message was sent does not exist anymore, or you are missing permissions to access it.";
 | 
			
		||||
 | 
			
		||||
                var channel = _cache.GetChannel(msg.Message.Channel);
 | 
			
		||||
                if (channel == null)
 | 
			
		||||
                    throw new PKError(error);
 | 
			
		||||
 | 
			
		||||
                if (!await ctx.CheckPermissionsInGuildChannel(channel,
 | 
			
		||||
                    PermissionSet.ViewChannel | PermissionSet.SendMessages
 | 
			
		||||
                ))
 | 
			
		||||
                    throw new PKError(error);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return msg;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -145,11 +159,20 @@ namespace PluralKit.Bot
 | 
			
		||||
                    throw Errors.MessageNotFound(messageId.Value);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var showContent = true;
 | 
			
		||||
            var noShowContentError = "Message deleted or inaccessible.";
 | 
			
		||||
 | 
			
		||||
            var channel = _cache.GetChannel(message.Message.Channel);
 | 
			
		||||
            if (channel == null)
 | 
			
		||||
                showContent = false;
 | 
			
		||||
            else if (!await ctx.CheckPermissionsInGuildChannel(channel, PermissionSet.ViewChannel))
 | 
			
		||||
                showContent = false;
 | 
			
		||||
 | 
			
		||||
            if (ctx.MatchRaw())
 | 
			
		||||
            {
 | 
			
		||||
                var discordMessage = await _rest.GetMessageOrNull(message.Message.Channel, message.Message.Mid);
 | 
			
		||||
                if (discordMessage == null)
 | 
			
		||||
                    throw new PKError("Message deleted or inaccessible.");
 | 
			
		||||
                if (discordMessage == null || !showContent)
 | 
			
		||||
                    throw new PKError(noShowContentError);
 | 
			
		||||
 | 
			
		||||
                var content = discordMessage.Content;
 | 
			
		||||
                if (content == null || content == "")
 | 
			
		||||
@@ -174,12 +197,15 @@ namespace PluralKit.Bot
 | 
			
		||||
 | 
			
		||||
            if (isDelete)
 | 
			
		||||
            {
 | 
			
		||||
                if (!showContent)
 | 
			
		||||
                    throw new PKError(noShowContentError);
 | 
			
		||||
 | 
			
		||||
                if (message.System.Id != ctx.System.Id)
 | 
			
		||||
                    throw new PKError("You can only delete your own messages.");
 | 
			
		||||
 | 
			
		||||
                await ctx.Rest.DeleteMessage(message.Message.Channel, message.Message.Mid);
 | 
			
		||||
 | 
			
		||||
                if (ctx.Guild != null)
 | 
			
		||||
                if (ctx.Channel.Id == message.Message.Channel)
 | 
			
		||||
                    await ctx.Rest.DeleteMessage(ctx.Message);
 | 
			
		||||
                else
 | 
			
		||||
                    await ctx.Rest.CreateReaction(ctx.Message.ChannelId, ctx.Message.Id, new() { Name = Emojis.Success });
 | 
			
		||||
@@ -197,7 +223,7 @@ namespace PluralKit.Bot
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await ctx.Reply(embed: await _embeds.CreateMessageInfoEmbed(message));
 | 
			
		||||
            await ctx.Reply(embed: await _embeds.CreateMessageInfoEmbed(message, showContent));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async Task DeleteCommandMessage(Context ctx, ulong messageId)
 | 
			
		||||
 
 | 
			
		||||
@@ -175,7 +175,7 @@ namespace PluralKit.Bot
 | 
			
		||||
 | 
			
		||||
                await _rest.CreateMessage(dm.Id, new MessageRequest
 | 
			
		||||
                {
 | 
			
		||||
                    Embed = await _embeds.CreateMessageInfoEmbed(msg)
 | 
			
		||||
                    Embed = await _embeds.CreateMessageInfoEmbed(msg, true)
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            catch (ForbiddenException) { } // No permissions to DM, can't check for this :(
 | 
			
		||||
 
 | 
			
		||||
@@ -275,7 +275,7 @@ namespace PluralKit.Bot
 | 
			
		||||
                .Build();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task<Embed> CreateMessageInfoEmbed(FullMessage msg)
 | 
			
		||||
        public async Task<Embed> CreateMessageInfoEmbed(FullMessage msg, bool showContent)
 | 
			
		||||
        {
 | 
			
		||||
            var channel = await _cache.GetOrFetchChannel(_rest, msg.Message.Channel);
 | 
			
		||||
            var ctx = LookupContext.ByNonOwner;
 | 
			
		||||
@@ -317,11 +317,15 @@ namespace PluralKit.Bot
 | 
			
		||||
            else if (userInfo != null) userStr = userInfo.NameAndMention();
 | 
			
		||||
            else userStr = $"*(deleted user {msg.Message.Sender})*";
 | 
			
		||||
 | 
			
		||||
            var content = serverMsg?.Content?.NormalizeLineEndSpacing();
 | 
			
		||||
            if (content == null || !showContent)
 | 
			
		||||
                content = "*(message contents deleted or inaccessible)*";
 | 
			
		||||
 | 
			
		||||
            // Put it all together
 | 
			
		||||
            var eb = new EmbedBuilder()
 | 
			
		||||
                .Author(new(msg.Member.NameFor(ctx), IconUrl: msg.Member.AvatarFor(ctx).TryGetCleanCdnUrl()))
 | 
			
		||||
                .Description(serverMsg?.Content?.NormalizeLineEndSpacing() ?? "*(message contents deleted or inaccessible)*")
 | 
			
		||||
                .Image(new(serverMsg?.Attachments?.FirstOrDefault()?.Url))
 | 
			
		||||
                .Description(content)
 | 
			
		||||
                .Image(showContent ? new(serverMsg?.Attachments?.FirstOrDefault()?.Url) : null)
 | 
			
		||||
                .Field(new("System",
 | 
			
		||||
                    msg.System.Name != null ? $"{msg.System.Name} (`{msg.System.Hid}`)" : $"`{msg.System.Hid}`", true))
 | 
			
		||||
                .Field(new("Member", $"{msg.Member.NameFor(ctx)} (`{msg.Member.Hid}`)", true))
 | 
			
		||||
@@ -329,7 +333,7 @@ namespace PluralKit.Bot
 | 
			
		||||
                .Timestamp(DiscordUtils.SnowflakeToInstant(msg.Message.Mid).ToDateTimeOffset().ToString("O"));
 | 
			
		||||
 | 
			
		||||
            var roles = memberInfo?.Roles?.ToList();
 | 
			
		||||
            if (roles != null && roles.Count > 0)
 | 
			
		||||
            if (roles != null && roles.Count > 0 && showContent)
 | 
			
		||||
            {
 | 
			
		||||
                var rolesString = string.Join(", ", roles
 | 
			
		||||
                    .Select(id =>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user