2021-08-27 11:03:47 -04:00
#nullable enable
2023-09-09 22:58:54 -07:00
using System ;
2021-10-29 16:42:10 -04:00
using System.Text ;
using System.Text.RegularExpressions ;
2021-05-03 12:33:30 +02:00
2022-06-19 20:28:55 -04:00
using Autofac ;
2021-08-25 14:36:13 -04:00
using Myriad.Builders ;
2021-07-28 02:23:01 -04:00
using Myriad.Cache ;
using Myriad.Extensions ;
2021-05-03 12:33:30 +02:00
using Myriad.Rest ;
2021-11-26 21:10:56 -05:00
using Myriad.Rest.Exceptions ;
2021-10-29 16:42:10 -04:00
using Myriad.Rest.Types ;
using Myriad.Rest.Types.Requests ;
2021-05-03 12:33:30 +02:00
using Myriad.Types ;
using NodaTime ;
2022-05-09 09:10:07 +12:00
using App.Metrics ;
2021-05-03 12:33:30 +02:00
using PluralKit.Core ;
2023-05-15 15:17:34 +00:00
using Myriad.Gateway ;
using Myriad.Utils ;
2021-05-03 12:33:30 +02:00
2021-11-26 21:10:56 -05:00
namespace PluralKit.Bot ;
public class ProxiedMessage
2021-05-03 12:33:30 +02:00
{
2021-11-26 21:10:56 -05:00
private static readonly Duration EditTimeout = Duration . FromMinutes ( 10 ) ;
2022-05-09 09:10:07 +12:00
private static readonly Duration ReproxyTimeout = Duration . FromMinutes ( 1 ) ;
2022-03-30 04:36:22 -04:00
2022-03-09 20:06:53 -05:00
// private readonly IDiscordCache _cache;
2022-05-09 09:10:07 +12:00
private readonly ModelRepository _repo ;
private readonly IMetrics _metrics ;
2021-11-26 21:10:56 -05:00
private readonly EmbedService _embeds ;
private readonly LogChannelService _logChannel ;
private readonly DiscordApiClient _rest ;
private readonly WebhookExecutorService _webhookExecutor ;
2022-05-09 09:10:07 +12:00
private readonly ProxyService _proxy ;
2022-08-27 18:57:57 +12:00
private readonly LastMessageCacheService _lastMessageCache ;
2024-08-16 16:10:55 +02:00
private readonly RedisService _redisService ;
2021-11-26 21:10:56 -05:00
2022-05-09 09:10:07 +12:00
public ProxiedMessage ( EmbedService embeds ,
DiscordApiClient rest , IMetrics metrics , ModelRepository repo , ProxyService proxy ,
2022-08-27 18:57:57 +12:00
WebhookExecutorService webhookExecutor , LogChannelService logChannel , IDiscordCache cache ,
2024-08-16 16:10:55 +02:00
LastMessageCacheService lastMessageCache , RedisService redisService )
2021-05-03 12:33:30 +02:00
{
2021-11-26 21:10:56 -05:00
_embeds = embeds ;
_rest = rest ;
_webhookExecutor = webhookExecutor ;
2022-05-09 09:10:07 +12:00
_repo = repo ;
2021-11-26 21:10:56 -05:00
_logChannel = logChannel ;
2022-03-09 20:06:53 -05:00
// _cache = cache;
2022-05-09 09:10:07 +12:00
_metrics = metrics ;
2022-06-10 18:49:36 -04:00
_proxy = proxy ;
2022-08-27 18:57:57 +12:00
_lastMessageCache = lastMessageCache ;
2024-08-16 16:10:55 +02:00
_redisService = redisService ;
2022-05-09 09:10:07 +12:00
}
2025-10-03 02:21:12 +00:00
public async Task ReproxyMessage ( Context ctx , ulong? messageId )
2022-05-09 09:10:07 +12:00
{
2025-10-03 02:21:12 +00:00
var ( msg , systemId ) = await GetMessageToEdit ( ctx , messageId , ReproxyTimeout , true ) ;
2022-05-09 09:10:07 +12:00
2022-11-23 09:17:19 +00:00
if ( ctx . System . Id ! = systemId )
2022-05-09 09:10:07 +12:00
throw new PKError ( "Can't reproxy a message sent by a different system." ) ;
// Get target member ID
var target = await ctx . MatchMember ( restrictToSystem : ctx . System . Id ) ;
if ( target = = null )
throw new PKError ( "Could not find a member to reproxy the message with." ) ;
// Fetch members and get the ProxyMember for `target`
2022-06-10 18:49:36 -04:00
List < ProxyMember > members ;
2022-05-09 09:10:07 +12:00
using ( _metrics . Measure . Timer . Time ( BotMetrics . ProxyMembersQueryTime ) )
2022-11-23 09:17:19 +00:00
members = ( await _repo . GetProxyMembers ( ctx . Author . Id , msg . Guild ! . Value ) ) . ToList ( ) ;
2022-05-09 09:10:07 +12:00
var match = members . Find ( x = > x . Id = = target . Id ) ;
if ( match = = null )
throw new PKError ( "Could not find a member to reproxy the message with." ) ;
try
{
2024-12-31 08:09:18 -07:00
await _proxy . ExecuteReproxy ( ctx . Message , msg , members , match , ctx . DefaultPrefix ) ;
2022-05-09 09:10:07 +12:00
if ( ctx . Guild = = null )
await _rest . CreateReaction ( ctx . Channel . Id , ctx . Message . Id , new Emoji { Name = Emojis . Success } ) ;
if ( ( await ctx . BotPermissions ) . HasFlag ( PermissionSet . ManageMessages ) )
await _rest . DeleteMessage ( ctx . Channel . Id , ctx . Message . Id ) ;
}
catch ( NotFoundException )
{
throw new PKError ( "Could not reproxy message." ) ;
}
2021-11-26 21:10:56 -05:00
}
2021-05-03 12:33:30 +02:00
2025-10-03 02:21:12 +00:00
public async Task EditMessage ( Context ctx , ulong? messageId , string newContent , bool useRegex , bool mutateSpace , bool append , bool prepend , bool clearEmbeds , bool clearAttachments )
2021-11-26 21:10:56 -05:00
{
2025-10-03 02:21:12 +00:00
var ( msg , systemId ) = await GetMessageToEdit ( ctx , messageId , EditTimeout , false ) ;
2022-01-07 14:06:37 -05:00
2022-11-23 09:17:19 +00:00
if ( ctx . System . Id ! = systemId )
2021-11-26 21:10:56 -05:00
throw new PKError ( "Can't edit a message sent by a different system." ) ;
2021-08-27 11:03:47 -04:00
2022-11-23 09:17:19 +00:00
var originalMsg = await _rest . GetMessageOrNull ( msg . Channel , msg . Mid ) ;
2022-04-07 03:43:46 -04:00
if ( originalMsg = = null )
throw new PKError ( "Could not edit message." ) ;
// Grab the original message content and new message content
var originalContent = originalMsg . Content ;
2022-12-31 19:24:19 +13:00
// Should we clear embeds?
2024-11-16 22:01:57 +01:00
if ( ( clearEmbeds | | clearAttachments ) & & newContent = = null )
2022-12-31 19:24:19 +13:00
newContent = originalMsg . Content ! ;
if ( newContent = = null )
throw new PKSyntaxError ( "You need to include the message to edit in." ) ;
2022-04-07 03:47:38 -04:00
2023-09-09 22:58:54 -07:00
// Can't append or prepend a Regex
if ( useRegex & & ( append | | prepend ) )
throw new PKError ( "You can't use the append or prepend options with a Regex." ) ;
// Use the Regex to substitute the message content
if ( useRegex )
{
const string regexErrorStr = "Could not parse Regex. The expected formats are s|X|Y or s|X|Y|F, where | is any character, X is a valid Regex to search for matches of, Y is a substitution string, and F is a set of Regex flags." ;
// Smallest valid Regex string is "s||"; 3 chars long
if ( newContent . Length < 3 | | ! newContent . StartsWith ( 's' ) )
throw new PKError ( regexErrorStr ) ;
var separator = newContent [ 1 ] ;
// s|X|Y => ["s", "X", "Y"]
// s|X|Y|F => ["s", "X", "Y", "F"] ("F" may be empty)
var splitString = newContent . Split ( separator ) ;
if ( splitString . Length ! = 3 & & splitString . Length ! = 4 )
throw new PKError ( regexErrorStr ) ;
var flags = splitString . Length = = 4 ? splitString [ 3 ] : "" ;
var regexOptions = RegexOptions . None ;
var globalMatch = false ;
// Parse flags
foreach ( char c in flags )
{
switch ( c )
{
case 'g' :
globalMatch = true ;
break ;
case 'i' :
regexOptions | = RegexOptions . IgnoreCase ;
break ;
case 'm' :
regexOptions | = RegexOptions . Multiline ;
break ;
case 'n' :
regexOptions | = RegexOptions . ExplicitCapture ;
break ;
case 's' :
regexOptions | = RegexOptions . Singleline ;
break ;
case 'x' :
regexOptions | = RegexOptions . IgnorePatternWhitespace ;
break ;
default :
throw new PKError ( $"Invalid Regex flag '{c}'. Valid flags include 'g', 'i', 'm', 'n', 's', and 'x'." ) ;
}
}
try
{
// I would use RegexOptions.NonBacktracking but that's only .NET 7 :(
var regex = new Regex ( splitString [ 1 ] , regexOptions , TimeSpan . FromSeconds ( 0.5 ) ) ;
var numMatches = globalMatch ? - 1 : 1 ; // Negative means all matches
newContent = regex . Replace ( originalContent ! , splitString [ 2 ] , numMatches ) ;
}
catch ( ArgumentException )
{
throw new PKError ( regexErrorStr ) ;
}
catch ( RegexMatchTimeoutException )
{
throw new PKError ( "Regex took too long to run." ) ;
}
}
2022-04-07 03:43:46 -04:00
// Append or prepend the new content to the original message content if needed.
2024-12-31 05:15:21 -07:00
// If no flag is supplied, the new contents will completely overwrite the old contents
2022-04-07 03:43:46 -04:00
// If both flags are specified. the message will be prepended AND appended
2023-09-09 22:58:54 -07:00
if ( append & & prepend )
newContent = $"{newContent}{mutateSpace}{originalContent}{mutateSpace}{newContent}" ;
else if ( append )
newContent = $"{originalContent}{mutateSpace}{newContent}" ;
else if ( prepend )
newContent = $"{newContent}{mutateSpace}{originalContent}" ;
2021-05-03 12:33:30 +02:00
2022-01-21 18:23:58 -05:00
if ( newContent . Length > 2000 )
throw new PKError ( "PluralKit cannot proxy messages over 2000 characters in length." ) ;
2024-12-31 05:15:21 -07:00
// We count as an empty message even if there's an embed because the only embeds pk proxies are reply embeds and those aren't message content
if ( newContent . Trim ( ) . Length = = 0 & & ( originalMsg . Attachments . Length = = 0 | | clearAttachments ) )
{
throw new PKError ( "This action would result in an empty message. If you wish to delete the message, react to it with \u274C." ) ;
}
2021-11-26 21:10:56 -05:00
try
{
var editedMsg =
2024-11-16 22:01:57 +01:00
await _webhookExecutor . EditWebhookMessage ( msg . Guild ? ? 0 , msg . Channel , msg . Mid , newContent , clearEmbeds , clearAttachments ) ;
2021-08-27 11:03:47 -04:00
2021-11-26 21:10:56 -05:00
if ( ctx . Guild = = null )
await _rest . CreateReaction ( ctx . Channel . Id , ctx . Message . Id , new Emoji { Name = Emojis . Success } ) ;
2021-07-17 20:39:12 -04:00
2024-08-16 16:10:55 +02:00
await _redisService . SetOriginalMid ( ctx . Message . Id , editedMsg . Id ) ;
2021-11-26 21:10:56 -05:00
if ( ( await ctx . BotPermissions ) . HasFlag ( PermissionSet . ManageMessages ) )
await _rest . DeleteMessage ( ctx . Channel . Id , ctx . Message . Id ) ;
2021-05-07 17:35:09 +01:00
2022-11-23 09:17:19 +00:00
await _logChannel . LogMessage ( msg , ctx . Message , editedMsg , originalMsg ! . Content ! ) ;
2021-05-03 12:33:30 +02:00
}
2021-11-26 21:10:56 -05:00
catch ( NotFoundException )
2021-05-03 12:33:30 +02:00
{
2021-11-26 21:10:56 -05:00
throw new PKError ( "Could not edit message." ) ;
}
2025-02-23 11:02:55 +00:00
catch ( BadRequestException e )
{
if ( e . Message = = "Voice messages cannot be edited" )
throw new PKError ( $"{e.Message}." ) ;
throw ;
}
2021-11-26 21:10:56 -05:00
}
2021-07-27 11:39:37 -04:00
2025-10-03 02:21:12 +00:00
private async Task < ( PKMessage , SystemId ) > GetMessageToEdit ( Context ctx , ulong? referencedMessage , Duration timeout , bool isReproxy )
2021-11-26 21:10:56 -05:00
{
2022-05-09 09:10:07 +12:00
var editType = isReproxy ? "reproxy" : "edit" ;
var editTypeAction = isReproxy ? "reproxied" : "edited" ;
2022-11-23 09:17:19 +00:00
PKMessage ? msg = null ;
2021-05-03 12:33:30 +02:00
2021-11-26 21:10:56 -05:00
if ( referencedMessage ! = null )
{
2022-06-06 00:59:53 +02:00
await using var conn = await ctx . Database . Obtain ( ) ;
2022-11-23 09:17:19 +00:00
msg = await ctx . Repository . GetMessage ( referencedMessage . Value ) ;
2021-07-27 11:39:37 -04:00
if ( msg = = null )
2021-11-26 21:10:56 -05:00
throw new PKError ( "This is not a message proxied by PluralKit." ) ;
}
2021-05-07 22:31:43 +01:00
2021-11-26 21:10:56 -05:00
if ( msg = = null )
{
if ( ctx . Guild = = null )
2022-05-09 09:10:07 +12:00
throw new PKSyntaxError ( $"You must use a message link to {editType} messages in DMs." ) ;
2021-07-27 11:39:37 -04:00
2022-11-23 09:17:19 +00:00
ulong? recent = null ;
2022-08-27 17:02:50 +12:00
if ( isReproxy )
2022-11-24 06:32:55 +00:00
recent = await ctx . Redis . GetLastMessage ( ctx . Author . Id , ctx . Channel . Id ) ;
2022-08-27 17:02:50 +12:00
else
recent = await FindRecentMessage ( ctx , timeout ) ;
2021-11-26 21:10:56 -05:00
if ( recent = = null )
2022-05-09 09:10:07 +12:00
throw new PKSyntaxError ( $"Could not find a recent message to {editType}." ) ;
2021-07-27 11:39:37 -04:00
2022-06-06 00:59:53 +02:00
await using var conn = await ctx . Database . Obtain ( ) ;
2022-11-23 09:17:19 +00:00
msg = await ctx . Repository . GetMessage ( recent . Value ) ;
2021-11-26 21:10:56 -05:00
if ( msg = = null )
2022-05-09 09:10:07 +12:00
throw new PKSyntaxError ( $"Could not find a recent message to {editType}." ) ;
2021-11-26 21:10:56 -05:00
}
2021-11-10 23:46:16 -05:00
2022-11-23 09:17:19 +00:00
var member = await ctx . Repository . GetMember ( msg . Member ! . Value ) ;
if ( member = = null )
throw new PKSyntaxError ( $"Could not find a recent message to {editType}." ) ;
if ( msg . Channel ! = ctx . Channel . Id )
2021-11-26 21:10:56 -05:00
{
var error =
"The channel where the message was sent does not exist anymore, or you are missing permissions to access it." ;
2021-11-10 23:46:16 -05:00
2022-11-23 09:17:19 +00:00
var channel = await _rest . GetChannelOrNull ( msg . Channel ) ;
2021-11-26 21:10:56 -05:00
if ( channel = = null )
throw new PKError ( error ) ;
if ( ! await ctx . CheckPermissionsInGuildChannel ( channel ,
2021-11-10 23:46:16 -05:00
PermissionSet . ViewChannel | PermissionSet . SendMessages
) )
2021-11-26 21:10:56 -05:00
throw new PKError ( error ) ;
2021-05-03 12:33:30 +02:00
}
2025-04-01 10:48:20 +00:00
var lastMessage = await _lastMessageCache . GetLastMessage ( ctx . Message . GuildId ? ? 0 , ctx . Message . ChannelId ) ;
2022-11-23 09:17:19 +00:00
var isLatestMessage = lastMessage ? . Current . Id = = ctx . Message . Id
? lastMessage ? . Previous ? . Id = = msg . Mid
: lastMessage ? . Current . Id = = msg . Mid ;
2022-08-27 17:02:50 +12:00
2022-11-23 09:17:19 +00:00
var msgTimestamp = DiscordUtils . SnowflakeToInstant ( msg . Mid ) ;
2022-08-27 17:02:50 +12:00
if ( isReproxy & & ! isLatestMessage )
if ( SystemClock . Instance . GetCurrentInstant ( ) - msgTimestamp > timeout )
throw new PKError ( $"The message is too old to be {editTypeAction}." ) ;
2022-05-09 09:10:07 +12:00
2022-11-23 09:17:19 +00:00
return ( msg , member . System ) ;
2021-11-26 21:10:56 -05:00
}
2021-08-27 11:03:47 -04:00
2022-11-24 06:32:55 +00:00
private async Task < ulong? > FindRecentMessage ( Context ctx , Duration timeout )
2021-11-26 21:10:56 -05:00
{
2022-11-24 06:32:55 +00:00
var lastMessage = await ctx . Redis . GetLastMessage ( ctx . Author . Id , ctx . Channel . Id ) ;
2021-11-26 21:10:56 -05:00
if ( lastMessage = = null )
return null ;
2021-05-03 12:33:30 +02:00
2022-11-24 06:32:55 +00:00
var timestamp = DiscordUtils . SnowflakeToInstant ( lastMessage . Value ) ;
2022-05-09 09:10:07 +12:00
if ( SystemClock . Instance . GetCurrentInstant ( ) - timestamp > timeout )
2021-11-26 21:10:56 -05:00
return null ;
return lastMessage ;
}
2025-10-03 02:21:12 +00:00
public async Task GetMessage ( Context ctx , ulong? messageId , ReplyFormat format , bool isDelete , bool author )
2021-11-26 21:10:56 -05:00
{
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." ) ;
2021-05-03 12:33:30 +02:00
}
2021-08-27 11:03:47 -04:00
2022-11-23 09:17:19 +00:00
var message = await ctx . Repository . GetFullMessage ( messageId . Value ) ;
2021-11-26 21:10:56 -05:00
if ( message = = null )
2021-08-25 14:36:13 -04:00
{
2025-06-08 19:52:37 +00:00
await GetCommandMessage ( ctx , messageId . Value , isDelete ) ;
return ;
2021-11-26 21:10:56 -05:00
}
2021-09-26 22:49:43 -04:00
2021-11-26 21:10:56 -05:00
var showContent = true ;
var noShowContentError = "Message deleted or inaccessible." ;
2021-08-25 14:36:13 -04:00
2022-03-09 20:06:53 -05:00
var channel = await _rest . GetChannelOrNull ( message . Message . Channel ) ;
2021-11-26 21:10:56 -05:00
if ( channel = = null )
showContent = false ;
else if ( ! await ctx . CheckPermissionsInGuildChannel ( channel , PermissionSet . ViewChannel ) )
showContent = false ;
2021-11-10 23:46:16 -05:00
2024-10-03 02:23:33 -06:00
if ( format ! = ReplyFormat . Standard )
2021-11-26 21:10:56 -05:00
{
var discordMessage = await _rest . GetMessageOrNull ( message . Message . Channel , message . Message . Mid ) ;
if ( discordMessage = = null | | ! showContent )
throw new PKError ( noShowContentError ) ;
2021-11-10 23:46:16 -05:00
2021-11-26 21:10:56 -05:00
var content = discordMessage . Content ;
if ( content = = null | | content = = "" )
2021-10-29 16:42:10 -04:00
{
2021-11-26 21:10:56 -05:00
await ctx . Reply ( "No message content found in that message." ) ;
2021-10-29 16:42:10 -04:00
return ;
}
2024-10-03 02:23:33 -06:00
if ( format = = ReplyFormat . Raw )
{
await ctx . Reply ( $"```{content}```" ) ;
if ( Regex . IsMatch ( content , "```.*```" , RegexOptions . Singleline ) )
{
var stream = new MemoryStream ( Encoding . UTF8 . GetBytes ( content ) ) ;
await ctx . Rest . CreateMessage (
ctx . Channel . Id ,
new MessageRequest
{
Content = $"{Emojis.Warn} Message contains codeblocks, raw source sent as an attachment."
} ,
new [ ] { new MultipartFile ( "message.txt" , stream , null , null , null ) } ) ;
}
return ;
}
2021-09-22 13:48:34 -04:00
2024-10-03 02:23:33 -06:00
if ( format = = ReplyFormat . Plaintext )
2021-08-25 14:36:13 -04:00
{
2024-10-03 02:23:33 -06:00
var eb = new EmbedBuilder ( )
. Description ( $"Showing contents of message {message.Message.Mid}" ) ;
await ctx . Reply ( content , embed : eb . Build ( ) ) ;
return ;
2021-08-25 14:36:13 -04:00
}
}
2021-09-26 22:49:43 -04:00
2021-11-26 21:10:56 -05:00
if ( isDelete )
2021-09-26 22:49:43 -04:00
{
2021-11-26 21:10:56 -05:00
if ( ! showContent )
throw new PKError ( noShowContentError ) ;
2021-09-26 22:49:43 -04:00
2024-11-05 21:29:57 -07:00
// if user has has a system and their system sent the message, or if user sent the message, do not error
if ( ! ( ( ctx . System ! = null & & message . System ? . Id = = ctx . System . Id ) | | message . Message . Sender = = ctx . Author . Id ) )
2021-11-26 21:10:56 -05:00
throw new PKError ( "You can only delete your own messages." ) ;
2021-09-26 22:49:43 -04:00
2021-11-26 21:10:56 -05:00
await ctx . Rest . DeleteMessage ( message . Message . Channel , message . Message . Mid ) ;
2021-09-26 22:49:43 -04:00
2021-11-26 21:10:56 -05:00
if ( ctx . Channel . Id = = message . Message . Channel )
2021-09-26 22:49:43 -04:00
await ctx . Rest . DeleteMessage ( ctx . Message ) ;
else
2021-11-26 21:10:56 -05:00
await ctx . Rest . CreateReaction ( ctx . Message . ChannelId , ctx . Message . Id ,
new Emoji { Name = Emojis . Success } ) ;
return ;
2021-09-26 22:49:43 -04:00
}
2021-11-26 21:10:56 -05:00
2025-10-03 02:21:12 +00:00
if ( author )
2021-11-26 21:10:56 -05:00
{
2022-03-09 20:06:53 -05:00
var user = await _rest . GetUser ( message . Message . Sender ) ;
2021-11-26 21:10:56 -05:00
var eb = new EmbedBuilder ( )
. Author ( new Embed . EmbedAuthor (
user ! = null
? $"{user.Username}#{user.Discriminator}"
: $"Deleted user ${message.Message.Sender}" ,
IconUrl : user ! = null ? user . AvatarUrl ( ) : null ) )
. Description ( message . Message . Sender . ToString ( ) ) ;
await ctx . Reply (
user ! = null ? $"{user.Mention()} ({user.Id})" : $"*(deleted user {message.Message.Sender})*" ,
eb . Build ( ) ) ;
return ;
}
2024-11-09 11:34:42 -07:00
await ctx . Reply ( embed : await _embeds . CreateMessageInfoEmbed ( message , showContent , ctx . Config ) ) ;
2021-11-26 21:10:56 -05:00
}
2025-06-08 19:52:37 +00:00
private async Task GetCommandMessage ( Context ctx , ulong messageId , bool isDelete )
2021-11-26 21:10:56 -05:00
{
2025-06-08 19:52:37 +00:00
var msg = await _repo . GetCommandMessage ( messageId ) ;
if ( msg = = null )
2021-11-26 21:10:56 -05:00
throw Errors . MessageNotFound ( messageId ) ;
2025-06-08 19:52:37 +00:00
if ( isDelete )
{
if ( msg . Sender ! = ctx . Author . Id )
throw new PKError ( "You can only delete command messages queried by this account." ) ;
await ctx . Rest . DeleteMessage ( msg . Channel , messageId ) ;
2021-11-26 21:10:56 -05:00
2025-06-08 19:52:37 +00:00
if ( ctx . Guild ! = null )
await ctx . Rest . DeleteMessage ( ctx . Message ) ;
else
await ctx . Rest . CreateReaction ( ctx . Message . ChannelId , ctx . Message . Id , new Emoji { Name = Emojis . Success } ) ;
return ;
}
var showContent = true ;
var channel = await _rest . GetChannelOrNull ( msg . Channel ) ;
if ( channel = = null )
showContent = false ;
else if ( ! await ctx . CheckPermissionsInGuildChannel ( channel , PermissionSet . ViewChannel ) )
showContent = false ;
2021-11-26 21:10:56 -05:00
2025-06-08 19:52:37 +00:00
await ctx . Reply ( embed : await _embeds . CreateCommandMessageInfoEmbed ( msg , showContent ) ) ;
2021-05-03 12:33:30 +02:00
}
2024-03-07 03:31:01 -08:00
}