Add message editing command

Signed-off-by: Ske <voltasalt@gmail.com>
This commit is contained in:
Ske
2021-05-03 12:33:30 +02:00
parent 33cabff359
commit 3d624b39e4
9 changed files with 173 additions and 11 deletions

View File

@@ -79,6 +79,7 @@ namespace PluralKit.Bot
public static Command Help = new Command("help", "help", "Shows help information about PluralKit");
public static Command Explain = new Command("explain", "explain", "Explains the basics of systems and proxying");
public static Command Message = new Command("message", "message <id|link> [delete|author]", "Looks up a proxied message");
public static Command MessageEdit = new Command("edit", "edit [link] <text>", "Edit a previously proxied message");
public static Command LogChannel = new Command("log channel", "log channel <channel>", "Designates a channel to post proxied messages to");
public static Command LogChannelClear = new Command("log channel", "log channel -clear", "Clears the currently set log channel");
public static Command LogEnable = new Command("log enable", "log enable all|<channel> [channel 2] [channel 3...]", "Enables message logging in certain channels");
@@ -160,6 +161,8 @@ namespace PluralKit.Bot
return ctx.Execute<Help>(Explain, m => m.Explain(ctx));
if (ctx.Match("message", "msg"))
return ctx.Execute<Misc>(Message, m => m.GetMessage(ctx));
if (ctx.Match("edit", "e"))
return ctx.Execute<MessageEdit>(MessageEdit, m => m.EditMessage(ctx));
if (ctx.Match("log"))
if (ctx.Match("channel"))
return ctx.Execute<ServerConfig>(LogChannel, m => m.SetLogChannel(ctx));

View File

@@ -0,0 +1,91 @@
#nullable enable
using System.Threading.Tasks;
using Myriad.Rest;
using Myriad.Rest.Exceptions;
using Myriad.Types;
using NodaTime;
using PluralKit.Core;
namespace PluralKit.Bot
{
public class MessageEdit
{
private static readonly Duration EditTimeout = Duration.FromMinutes(10);
private readonly IDatabase _db;
private readonly ModelRepository _repo;
private readonly IClock _clock;
private readonly DiscordApiClient _rest;
private readonly WebhookExecutorService _webhookExecutor;
public MessageEdit(IDatabase db, ModelRepository repo, IClock clock, DiscordApiClient rest, WebhookExecutorService webhookExecutor)
{
_db = db;
_repo = repo;
_clock = clock;
_rest = rest;
_webhookExecutor = webhookExecutor;
}
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();
try
{
await _webhookExecutor.EditWebhookMessage(msg.Channel, msg.Mid, newContent);
if (ctx.BotPermissions.HasFlag(PermissionSet.ManageMessages))
await _rest.DeleteMessage(ctx.Channel.Id, ctx.Message.Id);
}
catch (NotFoundException)
{
throw new PKError("Could not edit message.");
}
}
private async Task<PKMessage> GetMessageToEdit(Context ctx)
{
var referencedMessage = ctx.MatchMessage(false);
if (referencedMessage != null)
{
await using var conn = await _db.Obtain();
var msg = await _repo.GetMessage(conn, referencedMessage.Value);
if (msg == null)
throw new PKError("This is not a message proxied by PluralKit.");
return msg.Message;
}
var recent = await FindRecentMessage(ctx);
if (recent == null)
throw new PKError("Could not find a recent message to edit.");
return recent;
}
private async Task<PKMessage?> FindRecentMessage(Context ctx)
{
await using var conn = await _db.Obtain();
var lastMessage = await _repo.GetLastMessage(conn, ctx.Guild.Id, ctx.Channel.Id, ctx.Author.Id);
if (lastMessage == null)
return null;
var timestamp = DiscordUtils.SnowflakeToInstant(lastMessage.Mid);
if (_clock.GetCurrentInstant() - timestamp > EditTimeout)
return null;
return lastMessage;
}
}
}

View File

@@ -215,17 +215,16 @@ namespace PluralKit.Bot {
public async Task GetMessage(Context ctx)
{
var word = ctx.PopArgument() ?? throw new PKSyntaxError("You must pass a message ID or link.");
ulong messageId;
if (ulong.TryParse(word, out var id))
messageId = id;
else if (Regex.Match(word, "https://(?:\\w+.)?discord(?:app)?.com/channels/\\d+/\\d+/(\\d+)") is Match match && match.Success)
messageId = ulong.Parse(match.Groups[1].Value);
else throw new PKSyntaxError($"Could not parse {word.AsCode()} as a message ID or link.");
var message = await _db.Execute(c => _repo.GetMessage(c, messageId));
if (message == null) throw Errors.MessageNotFound(messageId);
var messageId = ctx.MatchMessage(true);
if (messageId == null)
{
if (!ctx.HasNext())
throw new PKSyntaxError("You must pass a message ID or link.");
throw new PKSyntaxError($"Could not parse {ctx.PeekArgument().AsCode()} as a message ID or link.");
}
var message = await _db.Execute(c => _repo.GetMessage(c, messageId.Value));
if (message == null) throw Errors.MessageNotFound(messageId.Value);
if (ctx.Match("delete") || ctx.MatchFlag("delete"))
{