@@ -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));
|
||||
|
91
PluralKit.Bot/Commands/MessageEdit.cs
Normal file
91
PluralKit.Bot/Commands/MessageEdit.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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"))
|
||||
{
|
||||
|
Reference in New Issue
Block a user