private async ValueTask HandleQueryReaction(MessageReactionAddEvent evt, FullMessage msg) { var guild = await _cache.GetGuild(evt.GuildId !.Value); // Try to DM the user info about the message try { var dm = await _dmCache.GetOrCreateDmChannel(evt.UserId); var embeds = new List <Embed>(); if (msg.Member != null) { embeds.Add(await _embeds.CreateMemberEmbed( msg.System, msg.Member, guild, LookupContext.ByNonOwner, DateTimeZone.Utc )); } embeds.Add(await _embeds.CreateMessageInfoEmbed(msg, true)); await _rest.CreateMessage(dm, new MessageRequest { Embeds = embeds.ToArray() }); } catch (ForbiddenException) { } // No permissions to DM, can't check for this :( await TryRemoveOriginalReaction(evt); }
private async ValueTask <bool> TryHandleCommand(int shardId, MessageCreateEvent evt, Guild?guild, Channel channel, MessageContext ctx) { var content = evt.Content; if (content == null) { return(false); } var ourUserId = await _cache.GetOwnUser(); // Check for command prefix if (!HasCommandPrefix(content, ourUserId, out var cmdStart) || cmdStart == content.Length) { return(false); } if (ctx.IsDeleting) { await _rest.CreateMessage(evt.ChannelId, new() { Content = $"{Emojis.Error} Your system is currently being deleted." + " Due to database issues, it is not possible to use commands while a system is being deleted. Please wait a few minutes and try again.", MessageReference = new(guild?.Id, channel.Id, evt.Id) }); return(true); } // Trim leading whitespace from command without actually modifying the string // This just moves the argPos pointer by however much whitespace is at the start of the post-argPos string var trimStartLengthDiff = content.Substring(cmdStart).Length - content.Substring(cmdStart).TrimStart().Length; cmdStart += trimStartLengthDiff; try { var system = ctx.SystemId != null ? await _repo.GetSystem(ctx.SystemId.Value) : null; var config = ctx.SystemId != null ? await _repo.GetSystemConfig(ctx.SystemId.Value) : null; await _tree.ExecuteCommand(new Context(_services, shardId, guild, channel, evt, cmdStart, system, config, ctx)); } catch (PKError) { // Only permission errors will ever bubble this far and be caught here instead of Context.Execute // so we just catch and ignore these. TODO: this may need to change. } return(true); }
public async Task <Message> Reply(string text = null, Embed embed = null, AllowedMentions?mentions = null) { var botPerms = await BotPermissions; if (!botPerms.HasFlag(PermissionSet.SendMessages)) { // Will be "swallowed" during the error handler anyway, this message is never shown. throw new PKError("PluralKit does not have permission to send messages in this channel."); } if (embed != null && !botPerms.HasFlag(PermissionSet.EmbedLinks)) { throw new PKError("PluralKit does not have permission to send embeds in this channel. Please ensure I have the **Embed Links** permission enabled."); } var msg = await Rest.CreateMessage(Channel.Id, new MessageRequest { Content = text, Embeds = embed != null ? new[] { embed } : null, // Default to an empty allowed mentions object instead of null (which means no mentions allowed) AllowedMentions = mentions ?? new AllowedMentions() }); if (embed != null) { // Sensitive information that might want to be deleted by :x: reaction is typically in an embed format (member cards, for example) // This may need to be changed at some point but works well enough for now await _commandMessageService.RegisterMessage(msg.Id, msg.ChannelId, Author.Id); } return(msg); }
private async ValueTask <bool> TryHandleProxy(MessageCreateEvent evt, Guild guild, Channel channel, MessageContext ctx) { var botPermissions = await _cache.PermissionsIn(channel.Id); try { return(await _proxy.HandleIncomingMessage(evt, ctx, guild, channel, ctx.AllowAutoproxy, botPermissions)); } // Catch any failed proxy checks so they get ignored in the global error handler catch (ProxyService.ProxyChecksFailedException) { } catch (PKError e) { // User-facing errors, print to the channel properly formatted if (botPermissions.HasFlag(PermissionSet.SendMessages)) { await _rest.CreateMessage(evt.ChannelId, new MessageRequest { Content = $"{Emojis.Error} {e.Message}" }); } } return(false); }
public async ValueTask LogMessage(MessageContext ctx, ProxyMatch proxy, Message trigger, ulong hookMessage) { var logChannel = await GetAndCheckLogChannel(ctx, trigger); if (logChannel == null) { return; } var triggerChannel = _cache.GetChannel(trigger.ChannelId); // Send embed! await using var conn = await _db.Obtain(); var embed = _embed.CreateLoggedMessageEmbed(await _repo.GetSystem(conn, ctx.SystemId.Value), await _repo.GetMember(conn, proxy.Member.Id), hookMessage, trigger.Id, trigger.Author, proxy.Content, triggerChannel); var url = $"https://discord.com/channels/{trigger.GuildId}/{trigger.ChannelId}/{hookMessage}"; await _rest.CreateMessage(logChannel.Id, new() { Content = url, Embed = embed }); }
private async ValueTask HandleQueryReaction(MessageReactionAddEvent evt, FullMessage msg) { var guild = _cache.GetGuild(evt.GuildId !.Value); // Try to DM the user info about the message try { var dm = await _cache.GetOrCreateDmChannel(_rest, evt.UserId); await _rest.CreateMessage(dm.Id, new MessageRequest { Embed = await _embeds.CreateMemberEmbed(msg.System, msg.Member, guild, LookupContext.ByNonOwner) }); await _rest.CreateMessage(dm.Id, new MessageRequest { Embed = await _embeds.CreateMessageInfoEmbed(msg) }); } catch (ForbiddenException) { } // No permissions to DM, can't check for this :( await TryRemoveOriginalReaction(evt); }
private async ValueTask <bool> TryHandleProxy(Shard shard, MessageCreateEvent evt, Guild guild, Channel channel, MessageContext ctx) { var botPermissions = _bot.PermissionsIn(channel.Id); try { return(await _proxy.HandleIncomingMessage(shard, evt, ctx, guild, channel, allowAutoproxy : ctx.AllowAutoproxy, botPermissions)); } catch (PKError e) { // User-facing errors, print to the channel properly formatted if (botPermissions.HasFlag(PermissionSet.SendMessages)) { await _rest.CreateMessage(evt.ChannelId, new MessageRequest { Content = $"{Emojis.Error} {e.Message}" }); } } return(false); }
public async Task SendErrorMessage(ulong channelId, string errorId) { var now = SystemClock.Instance.GetCurrentInstant(); if (!ShouldSendErrorMessage(channelId, now)) { _logger.Warning("Rate limited sending error message to {ChannelId} with error code {ErrorId}", channelId, errorId); _metrics.Measure.Meter.Mark(BotMetrics.ErrorMessagesSent, "throttled"); return; } var channelInfo = _botConfig.IsBetaBot ? "**#hi-please-break-the-beta-bot** on **[the support server *(click to join)*](https://discord.gg/THvbH59btW)**" : "**#bug-reports-and-errors** on **[the support server *(click to join)*](https://discord.gg/PczBt78)**"; var embed = new EmbedBuilder() .Color(0xE74C3C) .Title("Internal error occurred") .Description($"For support, please send the error code above in {channelInfo} with a description of what you were doing at the time.") .Footer(new Embed.EmbedFooter(errorId)) .Timestamp(now.ToDateTimeOffset().ToString("O")); try { await _rest.CreateMessage(channelId, new MessageRequest { Content = $"> **Error code:** `{errorId}`", Embeds = new[] { embed.Build() } }); _logger.Information("Sent error message to {ChannelId} with error code {ErrorId}", channelId, errorId); _metrics.Measure.Meter.Mark(BotMetrics.ErrorMessagesSent, "sent"); } catch (Exception e) { _logger.Error(e, "Error sending error message to {ChannelId}", channelId); _metrics.Measure.Meter.Mark(BotMetrics.ErrorMessagesSent, "failed"); throw; } }
public async ValueTask LogMessage(MessageContext ctx, PKMessage proxiedMessage, Message trigger, Message hookMessage, string oldContent = null) { var logChannelId = await GetAndCheckLogChannel(ctx, trigger, proxiedMessage); if (logChannelId == null) { return; } var triggerChannel = await _cache.GetChannel(proxiedMessage.Channel); var system = await _repo.GetSystem(ctx.SystemId.Value); var member = await _repo.GetMember(proxiedMessage.Member !.Value); // Send embed! var embed = _embed.CreateLoggedMessageEmbed(trigger, hookMessage, system.Hid, member, triggerChannel.Name, oldContent); var url = $"https://discord.com/channels/{proxiedMessage.Guild.Value}/{proxiedMessage.Channel}/{proxiedMessage.Mid}"; await _rest.CreateMessage(logChannelId.Value, new MessageRequest { Content = url, Embeds = new[] { embed } }); }
public async ValueTask LogMessage(MessageContext ctx, ProxyMatch proxy, Message trigger, ulong hookMessage) { if (ctx.SystemId == null || ctx.LogChannel == null || ctx.InLogBlacklist) { return; } // Find log channel and check if valid var logChannel = await FindLogChannel(trigger.GuildId !.Value, ctx.LogChannel.Value); if (logChannel == null || logChannel.Type != Channel.ChannelType.GuildText) { return; } var triggerChannel = _cache.GetChannel(trigger.ChannelId); // Check bot permissions var perms = _bot.PermissionsIn(logChannel.Id); if (!perms.HasFlag(PermissionSet.SendMessages | PermissionSet.EmbedLinks)) { _logger.Information( "Does not have permission to proxy log, ignoring (channel: {ChannelId}, guild: {GuildId}, bot permissions: {BotPermissions})", ctx.LogChannel.Value, trigger.GuildId !.Value, perms); return; } // Send embed! await using var conn = await _db.Obtain(); var embed = _embed.CreateLoggedMessageEmbed(await _repo.GetSystem(conn, ctx.SystemId.Value), await _repo.GetMember(conn, proxy.Member.Id), hookMessage, trigger.Id, trigger.Author, proxy.Content, triggerChannel); var url = $"https://discord.com/channels/{trigger.GuildId}/{trigger.ChannelId}/{hookMessage}"; await _rest.CreateMessage(logChannel.Id, new() { Content = url, Embed = embed }); }