private async Task <Message?> GetReferencedMessage(ulong channelId, ulong?referencedMessageId) { if (referencedMessageId == null) { return(null); } var botPermissions = _bot.PermissionsIn(channelId); if (!botPermissions.HasFlag(PermissionSet.ReadMessageHistory)) { _logger.Warning("Tried to get referenced message in channel {ChannelId} to reply but bot does not have Read Message History", channelId); return(null); } return(await _rest.GetMessage(channelId, referencedMessageId.Value)); }
public async Task EditMessage(Context ctx) { var msg = await GetMessageToEdit(ctx); if (!ctx.HasNext()) { throw new PKSyntaxError("You need to include the message to edit in."); } if (ctx.Author.Id != msg.Sender) { throw new PKError("Can't edit a message sent from a different account."); } var newContent = ctx.RemainderOrNull(); var originalMsg = await _rest.GetMessage(msg.Channel, msg.Mid); try { await _webhookExecutor.EditWebhookMessage(msg.Channel, msg.Mid, newContent); if (ctx.Guild == null) { await _rest.CreateReaction(ctx.Channel.Id, ctx.Message.Id, new() { Name = Emojis.Success }); } if (ctx.BotPermissions.HasFlag(PermissionSet.ManageMessages)) { await _rest.DeleteMessage(ctx.Channel.Id, ctx.Message.Id); } await _logChannel.LogEditedMessage(ctx.MessageContext, msg, ctx.Message, originalMsg !, newContent); } catch (NotFoundException) { throw new PKError("Could not edit message."); } }
public async Task <Embed> CreateMessageInfoEmbed(FullMessage msg) { var channel = await _cache.GetOrFetchChannel(_rest, msg.Message.Channel); var ctx = LookupContext.ByNonOwner; Message serverMsg = null; try { serverMsg = await _rest.GetMessage(msg.Message.Channel, msg.Message.Mid); } catch (ForbiddenException) { // no permission, couldn't fetch, oh well } // Need this whole dance to handle cases where: // - the user is deleted (userInfo == null) // - the bot's no longer in the server we're querying (channel == null) // - the member is no longer in the server we're querying (memberInfo == null) // TODO: optimize ordering here a bit with new cache impl; and figure what happens if bot leaves server -> channel still cached -> hits this bit and 401s? GuildMemberPartial memberInfo = null; User userInfo = null; if (channel != null) { GuildMember member = null; try { member = await _rest.GetGuildMember(channel.GuildId !.Value, msg.Message.Sender); } catch (ForbiddenException) { // no permission, couldn't fetch, oh well } if (member != null) { // Don't do an extra request if we already have this info from the member lookup userInfo = member.User; } memberInfo = member; } if (userInfo == null) { userInfo = await _cache.GetOrFetchUser(_rest, msg.Message.Sender); } // Calculate string displayed under "Sent by" string userStr; if (memberInfo != null && memberInfo.Nick != null) { userStr = $"**Username:** {userInfo.NameAndMention()}\n**Nickname:** {memberInfo.Nick}"; } else if (userInfo != null) { userStr = userInfo.NameAndMention(); } else { userStr = $"*(deleted user {msg.Message.Sender})*"; } // Put it all together var eb = new EmbedBuilder() .Author(new(msg.Member.NameFor(ctx), IconUrl: DiscordUtils.WorkaroundForUrlBug(msg.Member.AvatarFor(ctx)))) .Description(serverMsg?.Content?.NormalizeLineEndSpacing() ?? "*(message contents deleted or inaccessible)*") .Image(new(serverMsg?.Attachments?.FirstOrDefault()?.Url)) .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)) .Field(new("Sent by", userStr, true)) .Timestamp(DiscordUtils.SnowflakeToInstant(msg.Message.Mid).ToDateTimeOffset().ToString("O")); var roles = memberInfo?.Roles?.ToList(); if (roles != null && roles.Count > 0) { // TODO: what if role isn't in cache? figure out a fallback var rolesString = string.Join(", ", roles.Select(id => _cache.GetRole(id)) .OrderByDescending(role => role.Position) .Select(role => role.Name)); eb.Field(new($"Account roles ({roles.Count})", rolesString.Truncate(1024))); } return(eb.Build()); }