fix message edit embed, ignore pk;edit triggers
This commit is contained in:
parent
8231c57bdf
commit
7ea945b427
6 changed files with 63 additions and 15 deletions
|
|
@ -1,9 +1,13 @@
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
using Remora.Discord.API;
|
||||||
|
using Remora.Rest.Core;
|
||||||
|
|
||||||
namespace Catalogger.Backend.Bot;
|
namespace Catalogger.Backend.Bot;
|
||||||
|
|
||||||
public static class DiscordUtils
|
public static class DiscordUtils
|
||||||
{
|
{
|
||||||
|
public static readonly Snowflake PkUserId = DiscordSnowflake.New(466378653216014359);
|
||||||
|
|
||||||
public static readonly Color Red = Color.FromArgb(231, 76, 60);
|
public static readonly Color Red = Color.FromArgb(231, 76, 60);
|
||||||
public static readonly Color Purple = Color.FromArgb(155, 89, 182);
|
public static readonly Color Purple = Color.FromArgb(155, 89, 182);
|
||||||
}
|
}
|
||||||
|
|
@ -26,7 +26,6 @@ public class MessageCreateResponder(
|
||||||
: IResponder<IMessageCreate>
|
: IResponder<IMessageCreate>
|
||||||
{
|
{
|
||||||
private readonly ILogger _logger = logger.ForContext<MessageCreateResponder>();
|
private readonly ILogger _logger = logger.ForContext<MessageCreateResponder>();
|
||||||
private static readonly Snowflake PkUserId = DiscordSnowflake.New(466378653216014359);
|
|
||||||
|
|
||||||
public async Task<Result> RespondAsync(IMessageCreate msg, CancellationToken ct = default)
|
public async Task<Result> RespondAsync(IMessageCreate msg, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
|
|
@ -50,11 +49,11 @@ public class MessageCreateResponder(
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg.Author.ID == PkUserId)
|
if (msg.Author.ID == DiscordUtils.PkUserId)
|
||||||
_ = pkMessageHandler.HandlePkMessageAsync(msg);
|
_ = pkMessageHandler.HandlePkMessageAsync(msg);
|
||||||
if (msg.ApplicationID.IsDefined(out var appId) && appId == PkUserId)
|
if (msg.ApplicationID.Is(DiscordUtils.PkUserId))
|
||||||
_ = pkMessageHandler.HandleProxiedMessageAsync(msg.ID.Value);
|
_ = pkMessageHandler.HandleProxiedMessageAsync(msg.ID.Value);
|
||||||
else if (msg.ApplicationID.HasValue && appId == config.Discord.ApplicationId)
|
else if (msg.ApplicationID.HasValue && msg.ApplicationID.Is(config.Discord.ApplicationId))
|
||||||
{
|
{
|
||||||
db.IgnoredMessages.Add(new IgnoredMessage(msg.ID.Value));
|
db.IgnoredMessages.Add(new IgnoredMessage(msg.ID.Value));
|
||||||
await db.SaveChangesAsync(ct);
|
await db.SaveChangesAsync(ct);
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ using Catalogger.Backend.Database.Queries;
|
||||||
using Catalogger.Backend.Extensions;
|
using Catalogger.Backend.Extensions;
|
||||||
using Catalogger.Backend.Services;
|
using Catalogger.Backend.Services;
|
||||||
using Humanizer;
|
using Humanizer;
|
||||||
|
using Microsoft.VisualBasic;
|
||||||
using NodaTime;
|
using NodaTime;
|
||||||
using Remora.Discord.API;
|
using Remora.Discord.API;
|
||||||
using Remora.Discord.API.Abstractions.Gateway.Events;
|
using Remora.Discord.API.Abstractions.Gateway.Events;
|
||||||
|
|
@ -11,6 +12,7 @@ using Remora.Discord.API.Abstractions.Objects;
|
||||||
using Remora.Discord.API.Objects;
|
using Remora.Discord.API.Objects;
|
||||||
using Remora.Discord.Extensions.Embeds;
|
using Remora.Discord.Extensions.Embeds;
|
||||||
using Remora.Discord.Gateway.Responders;
|
using Remora.Discord.Gateway.Responders;
|
||||||
|
using Remora.Rest.Core;
|
||||||
using Remora.Results;
|
using Remora.Results;
|
||||||
|
|
||||||
namespace Catalogger.Backend.Bot.Responders;
|
namespace Catalogger.Backend.Bot.Responders;
|
||||||
|
|
@ -22,15 +24,18 @@ public class MessageDeleteResponder(
|
||||||
WebhookExecutorService webhookExecutor,
|
WebhookExecutorService webhookExecutor,
|
||||||
ChannelCacheService channelCache,
|
ChannelCacheService channelCache,
|
||||||
UserCacheService userCache,
|
UserCacheService userCache,
|
||||||
IClock clock) : IResponder<IMessageDelete>
|
IClock clock,
|
||||||
|
PluralkitApiService pluralkitApi) : IResponder<IMessageDelete>
|
||||||
{
|
{
|
||||||
private readonly ILogger _logger = logger.ForContext<MessageDeleteResponder>();
|
private readonly ILogger _logger = logger.ForContext<MessageDeleteResponder>();
|
||||||
|
|
||||||
|
private static bool MaybePkProxyTrigger(Snowflake id) => id.Timestamp > DateTimeOffset.Now - 1.Minutes();
|
||||||
|
|
||||||
public async Task<Result> RespondAsync(IMessageDelete ev, CancellationToken ct = default)
|
public async Task<Result> RespondAsync(IMessageDelete ev, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
if (!ev.GuildID.IsDefined()) return Result.Success;
|
if (!ev.GuildID.IsDefined()) return Result.Success;
|
||||||
|
|
||||||
if (ev.ID.Timestamp < DateTimeOffset.Now - 1.Minutes())
|
if (MaybePkProxyTrigger(ev.ID))
|
||||||
{
|
{
|
||||||
_logger.Debug(
|
_logger.Debug(
|
||||||
"Deleted message {MessageId} is less than 1 minute old, delaying 5 seconds to give PK time to catch up",
|
"Deleted message {MessageId} is less than 1 minute old, delaying 5 seconds to give PK time to catch up",
|
||||||
|
|
@ -59,6 +64,20 @@ public class MessageDeleteResponder(
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the message is an edit trigger message.
|
||||||
|
// If it is, the API will return a valid message for its ID, but the ID won't match either `Id` or `Original`.
|
||||||
|
// (We also won't have any system/member information stored for it)
|
||||||
|
if (msg is { System: null, Member: null } && MaybePkProxyTrigger(ev.ID) && false)
|
||||||
|
{
|
||||||
|
// TODO: remove the "false" if/when the API is updated to actually return this :neofox_woozy:
|
||||||
|
var pkMsg = await pluralkitApi.GetPluralKitMessageAsync(ev.ID.Value, ct);
|
||||||
|
if (pkMsg != null && pkMsg.Id != ev.ID.Value && pkMsg.Original != ev.ID.Value)
|
||||||
|
{
|
||||||
|
_logger.Debug("Deleted message {MessageId} is a `pk;edit` message, ignoring", ev.ID);
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
logChannel = webhookExecutor.GetLogChannel(guild, LogChannelType.MessageDelete, ev.ChannelID, msg.UserId);
|
logChannel = webhookExecutor.GetLogChannel(guild, LogChannelType.MessageDelete, ev.ChannelID, msg.UserId);
|
||||||
if (logChannel == null) return Result.Success;
|
if (logChannel == null) return Result.Success;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,8 @@ public class MessageUpdateResponder(
|
||||||
ChannelCacheService channelCache,
|
ChannelCacheService channelCache,
|
||||||
UserCacheService userCache,
|
UserCacheService userCache,
|
||||||
MessageRepository messageRepository,
|
MessageRepository messageRepository,
|
||||||
WebhookExecutorService webhookExecutor) : IResponder<IMessageUpdate>
|
WebhookExecutorService webhookExecutor,
|
||||||
|
PluralkitApiService pluralkitApi) : IResponder<IMessageUpdate>
|
||||||
{
|
{
|
||||||
private readonly ILogger _logger = logger.ForContext<MessageUpdateResponder>();
|
private readonly ILogger _logger = logger.ForContext<MessageUpdateResponder>();
|
||||||
|
|
||||||
|
|
@ -76,8 +77,7 @@ public class MessageUpdateResponder(
|
||||||
.WithFooter($"ID: {msg.ID}")
|
.WithFooter($"ID: {msg.ID}")
|
||||||
.WithTimestamp(msg.ID.Timestamp);
|
.WithTimestamp(msg.ID.Timestamp);
|
||||||
|
|
||||||
var fields = Enumerable.Range(0, msg.Content.Length / 1000)
|
var fields = ChunksUpTo(msg.Content, 1000)
|
||||||
.Select(i => msg.Content.Substring(i * 1000, 1000))
|
|
||||||
.Select<string, IEmbedField>((s, i) =>
|
.Select<string, IEmbedField>((s, i) =>
|
||||||
new EmbedField($"New content{(i != 0 ? " (cont.)" : "")}", s, false))
|
new EmbedField($"New content{(i != 0 ? " (cont.)" : "")}", s, false))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
@ -110,7 +110,16 @@ public class MessageUpdateResponder(
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
await messageRepository.UpdateMessageAsync(msg, ct);
|
if (!await messageRepository.UpdateMessageAsync(msg, ct) && msg.ApplicationID.Is(DiscordUtils.PkUserId))
|
||||||
|
{
|
||||||
|
_logger.Debug(
|
||||||
|
"Message {MessageId} wasn't stored yet and was proxied by PluralKit, fetching proxy information from its API",
|
||||||
|
msg.ID);
|
||||||
|
var pkMsg = await pluralkitApi.GetPluralKitMessageAsync(msg.ID.Value, ct);
|
||||||
|
if (pkMsg != null)
|
||||||
|
await messageRepository.SetProxiedMessageDataAsync(msg.ID.Value, pkMsg.Original, pkMsg.Sender,
|
||||||
|
pkMsg.System?.Id, pkMsg.Member?.Id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -122,4 +131,10 @@ public class MessageUpdateResponder(
|
||||||
evt.WebhookID, evt.Type.GetOrThrow(), evt.Activity, evt.Application, evt.ApplicationID, evt.MessageReference,
|
evt.WebhookID, evt.Type.GetOrThrow(), evt.Activity, evt.Application, evt.ApplicationID, evt.MessageReference,
|
||||||
evt.Flags, evt.ReferencedMessage, evt.Interaction, evt.Thread, evt.Components, evt.StickerItems, evt.Position,
|
evt.Flags, evt.ReferencedMessage, evt.Interaction, evt.Thread, evt.Components, evt.StickerItems, evt.Position,
|
||||||
evt.Resolved, evt.InteractionMetadata, evt.Poll);
|
evt.Resolved, evt.InteractionMetadata, evt.Poll);
|
||||||
|
|
||||||
|
private static IEnumerable<string> ChunksUpTo(string str, int maxChunkSize)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < str.Length; i += maxChunkSize)
|
||||||
|
yield return str.Substring(i, Math.Min(maxChunkSize, str.Length - i));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -36,7 +36,12 @@ public class MessageRepository(ILogger logger, DatabaseContext db, IEncryptionSe
|
||||||
await db.SaveChangesAsync(ct);
|
await db.SaveChangesAsync(ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task UpdateMessageAsync(IMessageCreate msg, CancellationToken ct = default)
|
/// <summary>
|
||||||
|
/// Updates an edited message.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>true if the message was already stored and got updated,
|
||||||
|
/// false if the message wasn't stored and was newly inserted.</returns>
|
||||||
|
public async Task<bool> UpdateMessageAsync(IMessageCreate msg, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
_logger.Debug("Updating message {MessageId}", msg.ID);
|
_logger.Debug("Updating message {MessageId}", msg.ID);
|
||||||
|
|
||||||
|
|
@ -44,7 +49,10 @@ public class MessageRepository(ILogger logger, DatabaseContext db, IEncryptionSe
|
||||||
var (isStored, _) = await HasProxyInfoAsync(msg.ID.Value);
|
var (isStored, _) = await HasProxyInfoAsync(msg.ID.Value);
|
||||||
if (!isStored)
|
if (!isStored)
|
||||||
{
|
{
|
||||||
|
_logger.Debug("Edited message {MessageId} is not stored yet, storing it", msg.ID);
|
||||||
await SaveMessageAsync(msg, ct);
|
await SaveMessageAsync(msg, ct);
|
||||||
|
await tx.CommitAsync(ct);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -62,9 +70,9 @@ public class MessageRepository(ILogger logger, DatabaseContext db, IEncryptionSe
|
||||||
|
|
||||||
db.Update(dbMsg);
|
db.Update(dbMsg);
|
||||||
await db.SaveChangesAsync(ct);
|
await db.SaveChangesAsync(ct);
|
||||||
}
|
|
||||||
|
|
||||||
await tx.CommitAsync(ct);
|
await tx.CommitAsync(ct);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Message?> GetMessageAsync(ulong id, CancellationToken ct = default)
|
public async Task<Message?> GetMessageAsync(ulong id, CancellationToken ct = default)
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,9 @@ public static class DiscordExtensions
|
||||||
return snowflake.Value.Value;
|
return snowflake.Value.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool Is(this Optional<Snowflake> s1, Snowflake s2) => s1.IsDefined(out var value) && value == s2;
|
||||||
|
public static bool Is(this Optional<Snowflake> s1, ulong s2) => s1.IsDefined(out var value) && value == s2;
|
||||||
|
|
||||||
public static T GetOrThrow<T>(this Result<T> result)
|
public static T GetOrThrow<T>(this Result<T> result)
|
||||||
{
|
{
|
||||||
if (result.Error != null) throw new DiscordRestException(result.Error.Message);
|
if (result.Error != null) throw new DiscordRestException(result.Error.Message);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue