diff --git a/src/NadekoBot/Modules/Administration/Self/DoAsUserMessage.cs b/src/NadekoBot/Modules/Administration/Self/DoAsUserMessage.cs new file mode 100644 index 000000000..1a65f0985 --- /dev/null +++ b/src/NadekoBot/Modules/Administration/Self/DoAsUserMessage.cs @@ -0,0 +1,138 @@ +using MessageType = Discord.MessageType; + +namespace NadekoBot.Modules.Administration; + +public sealed class DoAsUserMessage : IUserMessage +{ + private readonly string _message; + private IUserMessage _msg; + private readonly IUser _user; + + public DoAsUserMessage(SocketUserMessage msg, IUser user, string message) + { + _msg = msg; + _user = user; + _message = message; + } + + public ulong Id => _msg.Id; + + public DateTimeOffset CreatedAt => _msg.CreatedAt; + + public Task DeleteAsync(RequestOptions options = null) + { + return _msg.DeleteAsync(options); + } + + public Task AddReactionAsync(IEmote emote, RequestOptions options = null) + { + return _msg.AddReactionAsync(emote, options); + } + + public Task RemoveReactionAsync(IEmote emote, IUser user, RequestOptions options = null) + { + return _msg.RemoveReactionAsync(emote, user, options); + } + + public Task RemoveReactionAsync(IEmote emote, ulong userId, RequestOptions options = null) + { + return _msg.RemoveReactionAsync(emote, userId, options); + } + + public Task RemoveAllReactionsAsync(RequestOptions options = null) + { + return _msg.RemoveAllReactionsAsync(options); + } + + public Task RemoveAllReactionsForEmoteAsync(IEmote emote, RequestOptions options = null) + { + return _msg.RemoveAllReactionsForEmoteAsync(emote, options); + } + + public IAsyncEnumerable> GetReactionUsersAsync(IEmote emoji, int limit, + RequestOptions options = null) + { + return _msg.GetReactionUsersAsync(emoji, limit, options); + } + + public MessageType Type => _msg.Type; + + public MessageSource Source => _msg.Source; + + public bool IsTTS => _msg.IsTTS; + + public bool IsPinned => _msg.IsPinned; + + public bool IsSuppressed => _msg.IsSuppressed; + + public bool MentionedEveryone => _msg.MentionedEveryone; + + public string Content => _message; + + public string CleanContent => _msg.CleanContent; + + public DateTimeOffset Timestamp => _msg.Timestamp; + + public DateTimeOffset? EditedTimestamp => _msg.EditedTimestamp; + + public IMessageChannel Channel => _msg.Channel; + + public IUser Author => _user; + + public IReadOnlyCollection Attachments => _msg.Attachments; + + public IReadOnlyCollection Embeds => _msg.Embeds; + + public IReadOnlyCollection Tags => _msg.Tags; + + public IReadOnlyCollection MentionedChannelIds => _msg.MentionedChannelIds; + + public IReadOnlyCollection MentionedRoleIds => _msg.MentionedRoleIds; + + public IReadOnlyCollection MentionedUserIds => _msg.MentionedUserIds; + + public MessageActivity Activity => _msg.Activity; + + public MessageApplication Application => _msg.Application; + + public MessageReference Reference => _msg.Reference; + + public IReadOnlyDictionary Reactions => _msg.Reactions; + + public IReadOnlyCollection Components => _msg.Components; + + public IReadOnlyCollection Stickers => _msg.Stickers; + + public MessageFlags? Flags => _msg.Flags; + + public IMessageInteraction Interaction => _msg.Interaction; + + public Task ModifyAsync(Action func, RequestOptions options = null) + { + return _msg.ModifyAsync(func, options); + } + + public Task PinAsync(RequestOptions options = null) + { + return _msg.PinAsync(options); + } + + public Task UnpinAsync(RequestOptions options = null) + { + return _msg.UnpinAsync(options); + } + + public Task CrosspostAsync(RequestOptions options = null) + { + return _msg.CrosspostAsync(options); + } + + public string Resolve(TagHandling userHandling = TagHandling.Name, TagHandling channelHandling = TagHandling.Name, + TagHandling roleHandling = TagHandling.Name, + TagHandling everyoneHandling = TagHandling.Ignore, TagHandling emojiHandling = TagHandling.Name) + { + return _msg.Resolve(userHandling, channelHandling, roleHandling, everyoneHandling, emojiHandling); + } + + public IUserMessage ReferencedMessage => _msg.ReferencedMessage; +} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Administration/Self/SelfCommands.cs b/src/NadekoBot/Modules/Administration/Self/SelfCommands.cs index 257a0b8d4..fb81c86bd 100644 --- a/src/NadekoBot/Modules/Administration/Self/SelfCommands.cs +++ b/src/NadekoBot/Modules/Administration/Self/SelfCommands.cs @@ -35,6 +35,26 @@ public partial class Administration _medusaLoader = medusaLoader; } + [Cmd] + [OwnerOnly] + public async Task DoAs(IUser user, [Leftover] string message) + { + if (ctx.User is not IGuildUser { GuildPermissions.Administrator: true }) + return; + + if (ctx.Guild is SocketGuild sg && ctx.Channel is ISocketMessageChannel ch + && ctx.Message is SocketUserMessage msg) + { + var fakeMessage = new DoAsUserMessage(msg, user, message); + + await _cmdHandler.TryRunCommand(sg, ch, fakeMessage); + } + else + { + await ReplyErrorLocalizedAsync(strs.error_occured); + } + } + [Cmd] [RequireContext(ContextType.Guild)] [UserPerm(GuildPerm.Administrator)] diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index 3dc7cf26c..3cb047854 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -302,7 +302,7 @@ public class CommandHandler : INService, IReadyExecutor } public Task<(bool Success, string Error, CommandInfo Info)> ExecuteCommandAsync( - CommandContext context, + ICommandContext context, string input, int argPos, IServiceProvider serviceProvider, @@ -311,7 +311,7 @@ public class CommandHandler : INService, IReadyExecutor public async Task<(bool Success, string Error, CommandInfo Info)> ExecuteCommand( - CommandContext context, + ICommandContext context, string input, IServiceProvider services, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception) diff --git a/src/NadekoBot/data/aliases.yml b/src/NadekoBot/data/aliases.yml index 9bfbc1a07..1333478bc 100644 --- a/src/NadekoBot/data/aliases.yml +++ b/src/NadekoBot/data/aliases.yml @@ -1383,4 +1383,7 @@ patronmessage: eval: - eval autopublish: - - autopublish \ No newline at end of file + - autopublish +doas: + - doas + - execas \ No newline at end of file diff --git a/src/NadekoBot/data/strings/commands/commands.en-US.yml b/src/NadekoBot/data/strings/commands/commands.en-US.yml index 9d2f7a4b2..ebaf2e688 100644 --- a/src/NadekoBot/data/strings/commands/commands.en-US.yml +++ b/src/NadekoBot/data/strings/commands/commands.en-US.yml @@ -2345,4 +2345,8 @@ threaddelete: autopublish: desc: "Make the bot automatically publish all messages posted in the news channel this command was executed in." args: - - "" \ No newline at end of file + - "" +doas: + desc: "Execute the command as if you were the target user. Requires bot ownership and server administrator permission." + args: + - "@Thief .give all @Admin"