mirror of
				https://gitlab.com/Kwoth/nadekobot.git
				synced 2025-11-03 16:24:27 -05:00 
			
		
		
		
	Switch to discord.net 3.0.0
This commit is contained in:
		@@ -51,7 +51,8 @@ public sealed class Bot
 | 
				
			|||||||
            TotalShards = _creds.TotalShards,
 | 
					            TotalShards = _creds.TotalShards,
 | 
				
			||||||
            ShardId = shardId,
 | 
					            ShardId = shardId,
 | 
				
			||||||
            AlwaysDownloadUsers = false,
 | 
					            AlwaysDownloadUsers = false,
 | 
				
			||||||
            ExclusiveBulkDelete = true,
 | 
					            AlwaysResolveStickers = false,
 | 
				
			||||||
 | 
					            AlwaysDownloadDefaultStickers = false,
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        _commandService = new(new()
 | 
					        _commandService = new(new()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,12 +0,0 @@
 | 
				
			|||||||
namespace Discord;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public class BotPermAttribute : RequireBotPermissionAttribute
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    public BotPermAttribute(GuildPerm permission) : base((GuildPermission)permission)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public BotPermAttribute(ChannelPerm permission) : base((ChannelPermission)permission)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -4,26 +4,22 @@ using NadekoBot.Modules.Administration.Services;
 | 
				
			|||||||
namespace Discord;
 | 
					namespace Discord;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
 | 
					[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
 | 
				
			||||||
public class UserPermAttribute : PreconditionAttribute
 | 
					public class UserPermAttribute : RequireUserPermissionAttribute
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public RequireUserPermissionAttribute UserPermissionAttribute { get; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public UserPermAttribute(GuildPerm permission)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        UserPermissionAttribute = new((GuildPermission)permission);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public UserPermAttribute(ChannelPerm permission)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        UserPermissionAttribute = new((ChannelPermission)permission);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public override Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services)
 | 
					    public override Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var permService = services.GetRequiredService<DiscordPermOverrideService>();
 | 
					        var permService = services.GetRequiredService<DiscordPermOverrideService>();
 | 
				
			||||||
        if (permService.TryGetOverrides(context.Guild?.Id ?? 0, command.Name.ToUpperInvariant(), out var _))
 | 
					        if (permService.TryGetOverrides(context.Guild?.Id ?? 0, command.Name.ToUpperInvariant(), out var _))
 | 
				
			||||||
            return Task.FromResult(PreconditionResult.FromSuccess());
 | 
					            return Task.FromResult(PreconditionResult.FromSuccess());
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
        return UserPermissionAttribute.CheckPermissionsAsync(context, command, services);
 | 
					        return base.CheckPermissionsAsync(context, command, services);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public UserPermAttribute(GuildPerm permission) : base(permission)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public UserPermAttribute(ChannelPerm permission) : base(permission)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1,250 +0,0 @@
 | 
				
			|||||||
namespace Discord;
 | 
					 | 
				
			||||||
// just a copy paste from discord.net in order to rename it, for compatibility iwth v3 which is gonna use custom lib
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Summary:
 | 
					 | 
				
			||||||
//     Defines the available permissions for a channel.
 | 
					 | 
				
			||||||
[Flags]
 | 
					 | 
				
			||||||
public enum GuildPerm : ulong
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows creation of instant invites.
 | 
					 | 
				
			||||||
    CreateInstantInvite = 1,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows kicking members.
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Remarks:
 | 
					 | 
				
			||||||
    //     This permission requires the owner account to use two-factor authentication when
 | 
					 | 
				
			||||||
    //     used on a guild that has server-wide 2FA enabled.
 | 
					 | 
				
			||||||
    KickMembers = 2,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows banning members.
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Remarks:
 | 
					 | 
				
			||||||
    //     This permission requires the owner account to use two-factor authentication when
 | 
					 | 
				
			||||||
    //     used on a guild that has server-wide 2FA enabled.
 | 
					 | 
				
			||||||
    BanMembers = 4,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows all permissions and bypasses channel permission overwrites.
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Remarks:
 | 
					 | 
				
			||||||
    //     This permission requires the owner account to use two-factor authentication when
 | 
					 | 
				
			||||||
    //     used on a guild that has server-wide 2FA enabled.
 | 
					 | 
				
			||||||
    Administrator = 8,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows management and editing of channels.
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Remarks:
 | 
					 | 
				
			||||||
    //     This permission requires the owner account to use two-factor authentication when
 | 
					 | 
				
			||||||
    //     used on a guild that has server-wide 2FA enabled.
 | 
					 | 
				
			||||||
    ManageChannels = 16,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows management and editing of the guild.
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Remarks:
 | 
					 | 
				
			||||||
    //     This permission requires the owner account to use two-factor authentication when
 | 
					 | 
				
			||||||
    //     used on a guild that has server-wide 2FA enabled.
 | 
					 | 
				
			||||||
    ManageGuild = 32,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows for the addition of reactions to messages.
 | 
					 | 
				
			||||||
    AddReactions = 64,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows for viewing of audit logs.
 | 
					 | 
				
			||||||
    ViewAuditLog = 128,
 | 
					 | 
				
			||||||
    PrioritySpeaker = 256,
 | 
					 | 
				
			||||||
    ReadMessages = 1024,
 | 
					 | 
				
			||||||
    ViewChannel = 1024,
 | 
					 | 
				
			||||||
    SendMessages = 2048,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows for sending of text-to-speech messages.
 | 
					 | 
				
			||||||
    SendTTSMessages = 4096,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows for deletion of other users messages.
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Remarks:
 | 
					 | 
				
			||||||
    //     This permission requires the owner account to use two-factor authentication when
 | 
					 | 
				
			||||||
    //     used on a guild that has server-wide 2FA enabled.
 | 
					 | 
				
			||||||
    ManageMessages = 8192,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows links sent by users with this permission will be auto-embedded.
 | 
					 | 
				
			||||||
    EmbedLinks = 16384,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows for uploading images and files.
 | 
					 | 
				
			||||||
    AttachFiles = 32768,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows for reading of message history.
 | 
					 | 
				
			||||||
    ReadMessageHistory = 65536,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows for using the @everyone tag to notify all users in a channel, and the
 | 
					 | 
				
			||||||
    //     @here tag to notify all online users in a channel.
 | 
					 | 
				
			||||||
    MentionEveryone = 131072,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows the usage of custom emojis from other servers.
 | 
					 | 
				
			||||||
    UseExternalEmojis = 262144,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows for joining of a voice channel.
 | 
					 | 
				
			||||||
    Connect = 1048576,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows for speaking in a voice channel.
 | 
					 | 
				
			||||||
    Speak = 2097152,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows for muting members in a voice channel.
 | 
					 | 
				
			||||||
    MuteMembers = 4194304,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows for deafening of members in a voice channel.
 | 
					 | 
				
			||||||
    DeafenMembers = 8388608,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows for moving of members between voice channels.
 | 
					 | 
				
			||||||
    MoveMembers = 16777216,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows for using voice-activity-detection in a voice channel.
 | 
					 | 
				
			||||||
    UseVAD = 33554432,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows for modification of own nickname.
 | 
					 | 
				
			||||||
    ChangeNickname = 67108864,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows for modification of other users nicknames.
 | 
					 | 
				
			||||||
    ManageNicknames = 134217728,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows management and editing of roles.
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Remarks:
 | 
					 | 
				
			||||||
    //     This permission requires the owner account to use two-factor authentication when
 | 
					 | 
				
			||||||
    //     used on a guild that has server-wide 2FA enabled.
 | 
					 | 
				
			||||||
    ManageRoles = 268435456,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows management and editing of webhooks.
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Remarks:
 | 
					 | 
				
			||||||
    //     This permission requires the owner account to use two-factor authentication when
 | 
					 | 
				
			||||||
    //     used on a guild that has server-wide 2FA enabled.
 | 
					 | 
				
			||||||
    ManageWebhooks = 536870912,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows management and editing of emojis.
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Remarks:
 | 
					 | 
				
			||||||
    //     This permission requires the owner account to use two-factor authentication when
 | 
					 | 
				
			||||||
    //     used on a guild that has server-wide 2FA enabled.
 | 
					 | 
				
			||||||
    ManageEmojis = 1073741824
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// Summary:
 | 
					 | 
				
			||||||
//     Defines the available permissions for a channel.
 | 
					 | 
				
			||||||
[Flags]
 | 
					 | 
				
			||||||
public enum ChannelPerm : ulong
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows creation of instant invites.
 | 
					 | 
				
			||||||
    CreateInstantInvite = 1,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows management and editing of channels.
 | 
					 | 
				
			||||||
    ManageChannel = 16,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows for the addition of reactions to messages.
 | 
					 | 
				
			||||||
    AddReactions = 64,
 | 
					 | 
				
			||||||
    PrioritySpeaker = 256,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows for reading of messages. This flag is obsolete, use Discord.ChannelPermission.ViewChannel
 | 
					 | 
				
			||||||
    //     instead.
 | 
					 | 
				
			||||||
    ReadMessages = 1024,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows guild members to view a channel, which includes reading messages in text
 | 
					 | 
				
			||||||
    //     channels.
 | 
					 | 
				
			||||||
    ViewChannel = 1024,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows for sending messages in a channel.
 | 
					 | 
				
			||||||
    SendMessages = 2048,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows for sending of text-to-speech messages.
 | 
					 | 
				
			||||||
    SendTTSMessages = 4096,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows for deletion of other users messages.
 | 
					 | 
				
			||||||
    ManageMessages = 8192,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows links sent by users with this permission will be auto-embedded.
 | 
					 | 
				
			||||||
    EmbedLinks = 16384,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows for uploading images and files.
 | 
					 | 
				
			||||||
    AttachFiles = 32768,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows for reading of message history.
 | 
					 | 
				
			||||||
    ReadMessageHistory = 65536,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows for using the @everyone tag to notify all users in a channel, and the
 | 
					 | 
				
			||||||
    //     @here tag to notify all online users in a channel.
 | 
					 | 
				
			||||||
    MentionEveryone = 131072,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows the usage of custom emojis from other servers.
 | 
					 | 
				
			||||||
    UseExternalEmojis = 262144,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows for joining of a voice channel.
 | 
					 | 
				
			||||||
    Connect = 1048576,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows for speaking in a voice channel.
 | 
					 | 
				
			||||||
    Speak = 2097152,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows for muting members in a voice channel.
 | 
					 | 
				
			||||||
    MuteMembers = 4194304,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows for deafening of members in a voice channel.
 | 
					 | 
				
			||||||
    DeafenMembers = 8388608,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows for moving of members between voice channels.
 | 
					 | 
				
			||||||
    MoveMembers = 16777216,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows for using voice-activity-detection in a voice channel.
 | 
					 | 
				
			||||||
    UseVAD = 33554432,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows management and editing of roles.
 | 
					 | 
				
			||||||
    ManageRoles = 268435456,
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // Summary:
 | 
					 | 
				
			||||||
    //     Allows management and editing of webhooks.
 | 
					 | 
				
			||||||
    ManageWebhooks = 536870912
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -17,7 +17,9 @@ public sealed class ReactionEventWrapper : IDisposable
 | 
				
			|||||||
        _client.ReactionsCleared += Discord_ReactionsCleared;
 | 
					        _client.ReactionsCleared += Discord_ReactionsCleared;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private Task Discord_ReactionsCleared(Cacheable<IUserMessage, ulong> msg, ISocketMessageChannel channel)
 | 
					    private Task Discord_ReactionsCleared(
 | 
				
			||||||
 | 
					        Cacheable<IUserMessage, ulong> msg,
 | 
				
			||||||
 | 
					        Cacheable<IMessageChannel, ulong> channel)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        Task.Run(() =>
 | 
					        Task.Run(() =>
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -32,7 +34,9 @@ public sealed class ReactionEventWrapper : IDisposable
 | 
				
			|||||||
        return Task.CompletedTask;
 | 
					        return Task.CompletedTask;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private Task Discord_ReactionRemoved(Cacheable<IUserMessage, ulong> msg, ISocketMessageChannel channel, SocketReaction reaction)
 | 
					    private Task Discord_ReactionRemoved(
 | 
				
			||||||
 | 
					        Cacheable<IUserMessage, ulong> msg,
 | 
				
			||||||
 | 
					        Cacheable<IMessageChannel, ulong> cacheable, SocketReaction reaction)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        Task.Run(() =>
 | 
					        Task.Run(() =>
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -47,7 +51,10 @@ public sealed class ReactionEventWrapper : IDisposable
 | 
				
			|||||||
        return Task.CompletedTask;
 | 
					        return Task.CompletedTask;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private Task Discord_ReactionAdded(Cacheable<IUserMessage, ulong> msg, ISocketMessageChannel channel, SocketReaction reaction)
 | 
					    private Task Discord_ReactionAdded(
 | 
				
			||||||
 | 
					        Cacheable<IUserMessage, ulong> msg,
 | 
				
			||||||
 | 
					        Cacheable<IMessageChannel, ulong> cacheable,
 | 
				
			||||||
 | 
					        SocketReaction reaction)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        Task.Run(() =>
 | 
					        Task.Run(() =>
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -56,7 +63,9 @@ public sealed class ReactionEventWrapper : IDisposable
 | 
				
			|||||||
                if (msg.Id == Message.Id)
 | 
					                if (msg.Id == Message.Id)
 | 
				
			||||||
                    OnReactionAdded?.Invoke(reaction);
 | 
					                    OnReactionAdded?.Invoke(reaction);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            catch { }
 | 
					            catch
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return Task.CompletedTask;
 | 
					        return Task.CompletedTask;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,10 +6,15 @@ global using NadekoBot;
 | 
				
			|||||||
global using NadekoBot.Services;
 | 
					global using NadekoBot.Services;
 | 
				
			||||||
global using NadekoBot.Common;
 | 
					global using NadekoBot.Common;
 | 
				
			||||||
global using NadekoBot.Common.Attributes;
 | 
					global using NadekoBot.Common.Attributes;
 | 
				
			||||||
 | 
					// todo global using Nadekobot.Extensions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
global using Discord;
 | 
					global using Discord;
 | 
				
			||||||
global using Discord.Commands;
 | 
					global using Discord.Commands;
 | 
				
			||||||
global using Discord.Net;
 | 
					global using Discord.Net;
 | 
				
			||||||
global using Discord.WebSocket;
 | 
					global using Discord.WebSocket;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					global using GuildPerm = Discord.GuildPermission;
 | 
				
			||||||
 | 
					global using ChannelPerm = Discord.ChannelPermission;
 | 
				
			||||||
 | 
					global using BotPermAttribute = Discord.Commands.RequireBotPermissionAttribute;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
global using System.Collections.Concurrent;
 | 
					global using System.Collections.Concurrent;
 | 
				
			||||||
@@ -34,8 +34,8 @@ public partial class Administration : NadekoModule<AdministrationService>
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    [NadekoCommand, Aliases]
 | 
					    [NadekoCommand, Aliases]
 | 
				
			||||||
    [RequireContext(ContextType.Guild)]
 | 
					    [RequireContext(ContextType.Guild)]
 | 
				
			||||||
    [UserPerm(ChannelPerm.ManageChannel)]
 | 
					    [UserPerm(ChannelPerm.ManageChannels)]
 | 
				
			||||||
    [BotPerm(ChannelPerm.ManageChannel)]
 | 
					    [BotPerm(ChannelPerm.ManageChannels)]
 | 
				
			||||||
    public async Task Slowmode(StoopidTime time = null)
 | 
					    public async Task Slowmode(StoopidTime time = null)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var seconds = (int?)time?.Time.TotalSeconds ?? 0;
 | 
					        var seconds = (int?)time?.Time.TotalSeconds ?? 0;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -466,7 +466,7 @@ public partial class Administration
 | 
				
			|||||||
                if (user is null)
 | 
					                if (user is null)
 | 
				
			||||||
                    return;
 | 
					                    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                var ch = await user.GetOrCreateDMChannelAsync();
 | 
					                var ch = await user.CreateDMChannelAsync();
 | 
				
			||||||
                text = rep.Replace(text);
 | 
					                text = rep.Replace(text);
 | 
				
			||||||
                await ch.SendAsync(text);
 | 
					                await ch.SendAsync(text);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -253,7 +253,7 @@ public partial class Administration
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            user = user ?? (IGuildUser) ctx.User;
 | 
					            user = user ?? (IGuildUser) ctx.User;
 | 
				
			||||||
                
 | 
					                
 | 
				
			||||||
            var channel = await user.GetOrCreateDMChannelAsync();
 | 
					            var channel = await user.CreateDMChannelAsync();
 | 
				
			||||||
            var success = await _service.GreetDmTest(channel, user);
 | 
					            var success = await _service.GreetDmTest(channel, user);
 | 
				
			||||||
            if (success)
 | 
					            if (success)
 | 
				
			||||||
                await ctx.OkAsync();
 | 
					                await ctx.OkAsync();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,7 @@ using NadekoBot.Db;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace NadekoBot.Modules.Administration.Services;
 | 
					namespace NadekoBot.Modules.Administration.Services;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// todo if any activity...
 | 
				
			||||||
public class GameVoiceChannelService : INService
 | 
					public class GameVoiceChannelService : INService
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public ConcurrentHashSet<ulong> GameVoiceChannels { get; } = new ConcurrentHashSet<ulong>();
 | 
					    public ConcurrentHashSet<ulong> GameVoiceChannels { get; } = new ConcurrentHashSet<ulong>();
 | 
				
			||||||
@@ -24,7 +25,7 @@ public class GameVoiceChannelService : INService
 | 
				
			|||||||
        _client.GuildMemberUpdated += _client_GuildMemberUpdated;
 | 
					        _client.GuildMemberUpdated += _client_GuildMemberUpdated;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private Task _client_GuildMemberUpdated(SocketGuildUser before, SocketGuildUser after)
 | 
					    private Task _client_GuildMemberUpdated(Cacheable<SocketGuildUser, ulong> before, SocketGuildUser after)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var _ = Task.Run(async () =>
 | 
					        var _ = Task.Run(async () =>
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -32,15 +33,16 @@ public class GameVoiceChannelService : INService
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
                //if the user is in the voice channel and that voice channel is gvc
 | 
					                //if the user is in the voice channel and that voice channel is gvc
 | 
				
			||||||
                var vc = after.VoiceChannel;
 | 
					                var vc = after.VoiceChannel;
 | 
				
			||||||
                if (vc is null || !GameVoiceChannels.Contains(vc.Id))
 | 
					                if (vc is null || !GameVoiceChannels.Contains(vc.Id) || !before.HasValue)
 | 
				
			||||||
                    return;
 | 
					                    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                //if the activity has changed, and is a playing activity
 | 
					                //if the activity has changed, and is a playing activity
 | 
				
			||||||
                if (before.Activity != after.Activity
 | 
					                var oldActivity = before.Value.Activities.FirstOrDefault();
 | 
				
			||||||
                    && after.Activity is { Type: Discord.ActivityType.Playing })
 | 
					                var newActivity = after.Activities.FirstOrDefault();
 | 
				
			||||||
 | 
					                if (oldActivity != newActivity && newActivity is { Type: ActivityType.Playing })
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    //trigger gvc
 | 
					                    //trigger gvc
 | 
				
			||||||
                    await TriggerGvc(after, after.Activity.Name);
 | 
					                    await TriggerGvc(after, newActivity.Name);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -86,7 +88,7 @@ public class GameVoiceChannelService : INService
 | 
				
			|||||||
                if (!(usr is SocketGuildUser gUser))
 | 
					                if (!(usr is SocketGuildUser gUser))
 | 
				
			||||||
                    return;
 | 
					                    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                var game = gUser.Activity?.Name;
 | 
					                var game = gUser.Activities.FirstOrDefault()?.Name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (oldState.VoiceChannel == newState.VoiceChannel ||
 | 
					                if (oldState.VoiceChannel == newState.VoiceChannel ||
 | 
				
			||||||
                    newState.VoiceChannel is null)
 | 
					                    newState.VoiceChannel is null)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -567,12 +567,17 @@ public sealed class LogCommandService : ILogCommandService
 | 
				
			|||||||
        return isDeleted;
 | 
					        return isDeleted;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private Task _client_GuildUserUpdated(SocketGuildUser before, SocketGuildUser after)
 | 
					    private Task _client_GuildUserUpdated(Cacheable<SocketGuildUser, ulong> optBefore, SocketGuildUser after)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var _ = Task.Run(async () =>
 | 
					        var _ = Task.Run(async () =>
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            try
 | 
					            try
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 | 
					                var before = await optBefore.GetOrDownloadAsync();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (before is null)
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
                if (!GuildLogSettings.TryGetValue(before.Guild.Id, out var logSetting)
 | 
					                if (!GuildLogSettings.TryGetValue(before.Guild.Id, out var logSetting)
 | 
				
			||||||
                    || logSetting.LogIgnores.Any(ilc => ilc.LogItemId == after.Id && ilc.ItemType == IgnoredItemType.User))
 | 
					                    || logSetting.LogIgnores.Any(ilc => ilc.LogItemId == after.Id && ilc.ItemType == IgnoredItemType.User))
 | 
				
			||||||
                    return;
 | 
					                    return;
 | 
				
			||||||
@@ -642,10 +647,10 @@ public sealed class LogCommandService : ILogCommandService
 | 
				
			|||||||
                                return list;
 | 
					                                return list;
 | 
				
			||||||
                            });
 | 
					                            });
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    else if (before.Activity?.Name != after.Activity?.Name)
 | 
					                    else if (before.Activities.FirstOrDefault()?.Name != after.Activities.FirstOrDefault()?.Name)
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        var str =
 | 
					                        var str =
 | 
				
			||||||
                            $"👾`{PrettyCurrentTime(after.Guild)}`👤__**{after.Username}**__ is now playing **{after.Activity?.Name ?? "-"}**.";
 | 
					                            $"👾`{PrettyCurrentTime(after.Guild)}`👤__**{after.Username}**__ is now playing **{after.Activities.FirstOrDefault()?.Name ?? "-"}**.";
 | 
				
			||||||
                        PresenceUpdates.AddOrUpdate(logChannel,
 | 
					                        PresenceUpdates.AddOrUpdate(logChannel,
 | 
				
			||||||
                            new List<string>() {str}, (id, list) =>
 | 
					                            new List<string>() {str}, (id, list) =>
 | 
				
			||||||
                            {
 | 
					                            {
 | 
				
			||||||
@@ -857,19 +862,19 @@ public sealed class LogCommandService : ILogCommandService
 | 
				
			|||||||
        return Task.CompletedTask;
 | 
					        return Task.CompletedTask;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private Task _client_UserLeft(IGuildUser usr)
 | 
					    private Task _client_UserLeft(SocketGuild guild, SocketUser usr)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var _ = Task.Run(async () =>
 | 
					        var _ = Task.Run(async () =>
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            try
 | 
					            try
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out var logSetting)
 | 
					                if (!GuildLogSettings.TryGetValue(guild.Id, out var logSetting)
 | 
				
			||||||
                    || logSetting.UserLeftId is null
 | 
					                    || logSetting.UserLeftId is null
 | 
				
			||||||
                    || logSetting.LogIgnores.Any(ilc => ilc.LogItemId == usr.Id && ilc.ItemType == IgnoredItemType.User))
 | 
					                    || logSetting.LogIgnores.Any(ilc => ilc.LogItemId == usr.Id && ilc.ItemType == IgnoredItemType.User))
 | 
				
			||||||
                    return;
 | 
					                    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                ITextChannel logChannel;
 | 
					                ITextChannel logChannel;
 | 
				
			||||||
                if ((logChannel = await TryGetLogChannel(usr.Guild, logSetting, LogType.UserLeft)
 | 
					                if ((logChannel = await TryGetLogChannel(guild, logSetting, LogType.UserLeft)
 | 
				
			||||||
                        .ConfigureAwait(false)) is null)
 | 
					                        .ConfigureAwait(false)) is null)
 | 
				
			||||||
                    return;
 | 
					                    return;
 | 
				
			||||||
                var embed = _eb.Create()
 | 
					                var embed = _eb.Create()
 | 
				
			||||||
@@ -877,7 +882,7 @@ public sealed class LogCommandService : ILogCommandService
 | 
				
			|||||||
                    .WithTitle("❌ " + GetText(logChannel.Guild, strs.user_left))
 | 
					                    .WithTitle("❌ " + GetText(logChannel.Guild, strs.user_left))
 | 
				
			||||||
                    .WithDescription(usr.ToString())
 | 
					                    .WithDescription(usr.ToString())
 | 
				
			||||||
                    .AddField("Id", usr.Id.ToString())
 | 
					                    .AddField("Id", usr.Id.ToString())
 | 
				
			||||||
                    .WithFooter(CurrentTime(usr.Guild));
 | 
					                    .WithFooter(CurrentTime(guild));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (Uri.IsWellFormedUriString(usr.GetAvatarUrl(), UriKind.Absolute))
 | 
					                if (Uri.IsWellFormedUriString(usr.GetAvatarUrl(), UriKind.Absolute))
 | 
				
			||||||
                    embed.WithThumbnailUrl(usr.GetAvatarUrl());
 | 
					                    embed.WithThumbnailUrl(usr.GetAvatarUrl());
 | 
				
			||||||
@@ -1006,19 +1011,20 @@ public sealed class LogCommandService : ILogCommandService
 | 
				
			|||||||
        return Task.CompletedTask;
 | 
					        return Task.CompletedTask;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private Task _client_MessageDeleted(Cacheable<IMessage, ulong> optMsg, ISocketMessageChannel ch)
 | 
					    private Task _client_MessageDeleted(Cacheable<IMessage, ulong> optMsg, Cacheable<IMessageChannel, ulong> optCh)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var _ = Task.Run(async () =>
 | 
					        var _ = Task.Run(async () =>
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            try
 | 
					            try
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var msg = (optMsg.HasValue ? optMsg.Value : null) as IUserMessage;
 | 
					                var msg = optMsg.Value as IUserMessage;
 | 
				
			||||||
                if (msg is null || msg.IsAuthor(_client))
 | 
					                if (msg is null || msg.IsAuthor(_client))
 | 
				
			||||||
                    return;
 | 
					                    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (_ignoreMessageIds.Contains(msg.Id))
 | 
					                if (_ignoreMessageIds.Contains(msg.Id))
 | 
				
			||||||
                    return;
 | 
					                    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var ch = optCh.Value;
 | 
				
			||||||
                if (!(ch is ITextChannel channel))
 | 
					                if (!(ch is ITextChannel channel))
 | 
				
			||||||
                    return;
 | 
					                    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,14 +34,16 @@ public class RoleCommandsService : INService
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private Task _client_ReactionAdded(Cacheable<IUserMessage, ulong> msg, ISocketMessageChannel chan, SocketReaction reaction)
 | 
					    private Task _client_ReactionAdded(Cacheable<IUserMessage, ulong> msg,
 | 
				
			||||||
 | 
					        Cacheable<IMessageChannel, ulong> chan,
 | 
				
			||||||
 | 
					        SocketReaction reaction)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        _ = Task.Run(async () =>
 | 
					        _ = Task.Run(async () =>
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (!reaction.User.IsSpecified ||
 | 
					            if (!reaction.User.IsSpecified ||
 | 
				
			||||||
                reaction.User.Value.IsBot ||
 | 
					                reaction.User.Value.IsBot ||
 | 
				
			||||||
                reaction.User.Value is not SocketGuildUser gusr ||
 | 
					                reaction.User.Value is not SocketGuildUser gusr ||
 | 
				
			||||||
                chan is not SocketGuildChannel gch ||
 | 
					                chan.Value is not SocketGuildChannel gch ||
 | 
				
			||||||
                !_models.TryGetValue(gch.Guild.Id, out var confs))
 | 
					                !_models.TryGetValue(gch.Guild.Id, out var confs))
 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -93,7 +95,9 @@ public class RoleCommandsService : INService
 | 
				
			|||||||
        return Task.CompletedTask;
 | 
					        return Task.CompletedTask;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private Task _client_ReactionRemoved(Cacheable<IUserMessage, ulong> msg, ISocketMessageChannel chan, SocketReaction reaction)
 | 
					    private Task _client_ReactionRemoved(Cacheable<IUserMessage, ulong> msg,
 | 
				
			||||||
 | 
					        Cacheable<IMessageChannel, ulong> chan,
 | 
				
			||||||
 | 
					        SocketReaction reaction)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        _ = Task.Run(async () =>
 | 
					        _ = Task.Run(async () =>
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -104,7 +108,7 @@ public class RoleCommandsService : INService
 | 
				
			|||||||
                    reaction.User.Value is not SocketGuildUser gusr)
 | 
					                    reaction.User.Value is not SocketGuildUser gusr)
 | 
				
			||||||
                    return;
 | 
					                    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (chan is not SocketGuildChannel gch)
 | 
					                if (chan.Value is not SocketGuildChannel gch)
 | 
				
			||||||
                    return;
 | 
					                    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (!_models.TryGetValue(gch.Guild.Id, out var confs))
 | 
					                if (!_models.TryGetValue(gch.Guild.Id, out var confs))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -203,7 +203,7 @@ public sealed class SelfService : ILateExecutor, IReadyExecutor, INService
 | 
				
			|||||||
            if (user is null)
 | 
					            if (user is null)
 | 
				
			||||||
                return Task.FromResult<IDMChannel>(null);
 | 
					                return Task.FromResult<IDMChannel>(null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return user.GetOrCreateDMChannelAsync();
 | 
					            return user.CreateDMChannelAsync();
 | 
				
			||||||
        })).ConfigureAwait(false);
 | 
					        })).ConfigureAwait(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ownerChannels = channels.Where(x => x != null)
 | 
					        ownerChannels = channels.Where(x => x != null)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -61,7 +61,7 @@ public partial class Administration
 | 
				
			|||||||
            var dmFailed = false;
 | 
					            var dmFailed = false;
 | 
				
			||||||
            try
 | 
					            try
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                await (await user.GetOrCreateDMChannelAsync().ConfigureAwait(false)).EmbedAsync(_eb.Create().WithErrorColor()
 | 
					                await user.EmbedAsync(_eb.Create().WithErrorColor()
 | 
				
			||||||
                        .WithDescription(GetText(strs.warned_on(ctx.Guild.ToString())))
 | 
					                        .WithDescription(GetText(strs.warned_on(ctx.Guild.ToString())))
 | 
				
			||||||
                        .AddField(GetText(strs.moderator), ctx.User.ToString())
 | 
					                        .AddField(GetText(strs.moderator), ctx.User.ToString())
 | 
				
			||||||
                        .AddField(GetText(strs.reason), reason ?? "-"))
 | 
					                        .AddField(GetText(strs.reason), reason ?? "-"))
 | 
				
			||||||
@@ -449,8 +449,7 @@ public partial class Administration
 | 
				
			|||||||
                    var embed = _service.GetBanUserDmEmbed(Context, guildUser, defaultMessage, msg, time.Time);
 | 
					                    var embed = _service.GetBanUserDmEmbed(Context, guildUser, defaultMessage, msg, time.Time);
 | 
				
			||||||
                    if (embed is not null)
 | 
					                    if (embed is not null)
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        var userChannel = await guildUser.GetOrCreateDMChannelAsync();
 | 
					                        await guildUser.SendAsync(embed);
 | 
				
			||||||
                        await userChannel.SendAsync(embed);
 | 
					 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                catch
 | 
					                catch
 | 
				
			||||||
@@ -520,8 +519,7 @@ public partial class Administration
 | 
				
			|||||||
                var embed = _service.GetBanUserDmEmbed(Context, user, defaultMessage, msg, null);
 | 
					                var embed = _service.GetBanUserDmEmbed(Context, user, defaultMessage, msg, null);
 | 
				
			||||||
                if (embed is not null)
 | 
					                if (embed is not null)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    var userChannel = await user.GetOrCreateDMChannelAsync();
 | 
					                    await ctx.User.SendAsync(embed);
 | 
				
			||||||
                    await userChannel.SendAsync(embed);
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            catch
 | 
					            catch
 | 
				
			||||||
@@ -596,7 +594,6 @@ public partial class Administration
 | 
				
			|||||||
            
 | 
					            
 | 
				
			||||||
        private async Task InternalBanMessageTest(string reason, TimeSpan? duration)
 | 
					        private async Task InternalBanMessageTest(string reason, TimeSpan? duration)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var dmChannel = await ctx.User.GetOrCreateDMChannelAsync();
 | 
					 | 
				
			||||||
            var defaultMessage = GetText(strs.bandm(Format.Bold(ctx.Guild.Name), reason));
 | 
					            var defaultMessage = GetText(strs.bandm(Format.Bold(ctx.Guild.Name), reason));
 | 
				
			||||||
            var embed = _service.GetBanUserDmEmbed(Context,
 | 
					            var embed = _service.GetBanUserDmEmbed(Context,
 | 
				
			||||||
                (IGuildUser)ctx.User,
 | 
					                (IGuildUser)ctx.User,
 | 
				
			||||||
@@ -612,7 +609,7 @@ public partial class Administration
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
                try
 | 
					                try
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    await dmChannel.SendAsync(embed);
 | 
					                    await ctx.User.SendAsync(embed);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                catch (Exception)
 | 
					                catch (Exception)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,7 +13,7 @@ public static class CustomReactionExtensions
 | 
				
			|||||||
        DiscordSocketClient client, bool sanitize)
 | 
					        DiscordSocketClient client, bool sanitize)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var channel = cr.DmResponse
 | 
					        var channel = cr.DmResponse
 | 
				
			||||||
            ? await ctx.Author.GetOrCreateDMChannelAsync().ConfigureAwait(false)
 | 
					            ? await ctx.Author.CreateDMChannelAsync().ConfigureAwait(false)
 | 
				
			||||||
            : ctx.Channel;
 | 
					            : ctx.Channel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        var trigger = cr.Trigger.ResolveTriggerString(client);
 | 
					        var trigger = cr.Trigger.ResolveTriggerString(client);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -120,7 +120,7 @@ public class GameStatusEvent : ICurrencyEvent
 | 
				
			|||||||
        return _embedFunc(CurrencyEvent.Type.GameStatus, _opts, pot);
 | 
					        return _embedFunc(CurrencyEvent.Type.GameStatus, _opts, pot);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private async Task OnMessageDeleted(Cacheable<IMessage, ulong> msg, ISocketMessageChannel _)
 | 
					    private async Task OnMessageDeleted(Cacheable<IMessage, ulong> msg, Cacheable<IMessageChannel, ulong> cacheable)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (msg.Id == _msg.Id)
 | 
					        if (msg.Id == _msg.Id)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -123,7 +123,7 @@ public class ReactionEvent : ICurrencyEvent
 | 
				
			|||||||
        return _embedFunc(CurrencyEvent.Type.Reaction, _opts, pot);
 | 
					        return _embedFunc(CurrencyEvent.Type.Reaction, _opts, pot);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private async Task OnMessageDeleted(Cacheable<IMessage, ulong> msg, ISocketMessageChannel _)
 | 
					    private async Task OnMessageDeleted(Cacheable<IMessage, ulong> msg, Cacheable<IMessageChannel, ulong> cacheable)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (msg.Id == _msg.Id)
 | 
					        if (msg.Id == _msg.Id)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -150,7 +150,7 @@ public class ReactionEvent : ICurrencyEvent
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private Task HandleReaction(Cacheable<IUserMessage, ulong> msg,
 | 
					    private Task HandleReaction(Cacheable<IUserMessage, ulong> msg,
 | 
				
			||||||
        ISocketMessageChannel ch, SocketReaction r)
 | 
					        Cacheable<IMessageChannel, ulong> cacheable, SocketReaction r)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var _ = Task.Run(() =>
 | 
					        var _ = Task.Run(() =>
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -160,7 +160,7 @@ public partial class Gambling
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    try
 | 
					                    try
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        await (await ctx.User.GetOrCreateDMChannelAsync().ConfigureAwait(false))
 | 
					                        await ctx.User
 | 
				
			||||||
                            .EmbedAsync(_eb.Create().WithOkColor()
 | 
					                            .EmbedAsync(_eb.Create().WithOkColor()
 | 
				
			||||||
                                .WithTitle(GetText(strs.shop_purchase(ctx.Guild.Name)))
 | 
					                                .WithTitle(GetText(strs.shop_purchase(ctx.Guild.Name)))
 | 
				
			||||||
                                .AddField(GetText(strs.item), item.Text, false)
 | 
					                                .AddField(GetText(strs.item), item.Text, false)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -274,7 +274,7 @@ public class Help : NadekoModule<HelpService>
 | 
				
			|||||||
        if (com is null)
 | 
					        if (com is null)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var ch = channel is ITextChannel
 | 
					            var ch = channel is ITextChannel
 | 
				
			||||||
                ? await ((IGuildUser)ctx.User).GetOrCreateDMChannelAsync().ConfigureAwait(false)
 | 
					                ? await ctx.User.CreateDMChannelAsync().ConfigureAwait(false)
 | 
				
			||||||
                : channel;
 | 
					                : channel;
 | 
				
			||||||
            try
 | 
					            try
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -132,9 +132,9 @@ public class HelpService : ILateExecutor, INService
 | 
				
			|||||||
        var userPermString = string.Empty;
 | 
					        var userPermString = string.Empty;
 | 
				
			||||||
        if (userPerm is not null)
 | 
					        if (userPerm is not null)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (userPerm.UserPermissionAttribute.ChannelPermission is { } cPerm)
 | 
					            if (userPerm.ChannelPermission is { } cPerm)
 | 
				
			||||||
                userPermString = GetPreconditionString((ChannelPerm) cPerm);
 | 
					                userPermString = GetPreconditionString((ChannelPerm) cPerm);
 | 
				
			||||||
            if (userPerm.UserPermissionAttribute.GuildPermission is { } gPerm)
 | 
					            if (userPerm.GuildPermission is { } gPerm)
 | 
				
			||||||
                userPermString = GetPreconditionString((GuildPerm) gPerm);
 | 
					                userPermString = GetPreconditionString((GuildPerm) gPerm);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,7 +25,9 @@ public sealed class AyuVoiceStateService : INService
 | 
				
			|||||||
            .GetProperties(BindingFlags.NonPublic | BindingFlags.Instance)
 | 
					            .GetProperties(BindingFlags.NonPublic | BindingFlags.Instance)
 | 
				
			||||||
            .First(x => x.Name == "ApiClient" && x.PropertyType.Name == "DiscordSocketApiClient");
 | 
					            .First(x => x.Name == "ApiClient" && x.PropertyType.Name == "DiscordSocketApiClient");
 | 
				
			||||||
        _dnetApiClient = prop.GetValue(_client, null);
 | 
					        _dnetApiClient = prop.GetValue(_client, null);
 | 
				
			||||||
        _sendVoiceStateUpdateMethodInfo = _dnetApiClient.GetType().GetMethod("SendVoiceStateUpdateAsync");
 | 
					        _sendVoiceStateUpdateMethodInfo = _dnetApiClient.GetType()
 | 
				
			||||||
 | 
					            .GetMethod("SendVoiceStateUpdateAsync",
 | 
				
			||||||
 | 
					                types: new[] { typeof(ulong), typeof(ulong?), typeof(bool), typeof(bool), typeof(RequestOptions) });
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
        _client.LeftGuild += ClientOnLeftGuild;
 | 
					        _client.LeftGuild += ClientOnLeftGuild;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,8 +27,8 @@ public partial class Utility
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        [NadekoCommand, Aliases]
 | 
					        [NadekoCommand, Aliases]
 | 
				
			||||||
        [RequireContext(ContextType.Guild)]
 | 
					        [RequireContext(ContextType.Guild)]
 | 
				
			||||||
        [BotPerm(ChannelPerm.ManageChannel)]
 | 
					        [BotPerm(ChannelPerm.ManageChannels)]
 | 
				
			||||||
        [UserPerm(ChannelPerm.ManageChannel)]
 | 
					        [UserPerm(ChannelPerm.ManageChannels)]
 | 
				
			||||||
        public async Task InviteList(int page = 1, [Leftover]ITextChannel ch = null)
 | 
					        public async Task InviteList(int page = 1, [Leftover]ITextChannel ch = null)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (--page < 0)
 | 
					            if (--page < 0)
 | 
				
			||||||
@@ -76,8 +76,8 @@ public partial class Utility
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        [NadekoCommand, Aliases]
 | 
					        [NadekoCommand, Aliases]
 | 
				
			||||||
        [RequireContext(ContextType.Guild)]
 | 
					        [RequireContext(ContextType.Guild)]
 | 
				
			||||||
        [BotPerm(ChannelPerm.ManageChannel)]
 | 
					        [BotPerm(ChannelPerm.ManageChannels)]
 | 
				
			||||||
        [UserPerm(ChannelPerm.ManageChannel)]
 | 
					        [UserPerm(ChannelPerm.ManageChannels)]
 | 
				
			||||||
        public async Task InviteDelete(int index)
 | 
					        public async Task InviteDelete(int index)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (--index < 0)
 | 
					            if (--index < 0)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -298,8 +298,7 @@ public class PatreonRewardsService : INService
 | 
				
			|||||||
            if (user is null)
 | 
					            if (user is null)
 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
                
 | 
					                
 | 
				
			||||||
            var channel = await user.GetOrCreateDMChannelAsync();
 | 
					            await user.SendConfirmAsync(_eb, message);
 | 
				
			||||||
            await channel.SendConfirmAsync(_eb, message);
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch
 | 
					        catch
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -152,7 +152,7 @@ public class RemindService : INService
 | 
				
			|||||||
                var user = _client.GetUser(r.ChannelId);
 | 
					                var user = _client.GetUser(r.ChannelId);
 | 
				
			||||||
                if (user is null)
 | 
					                if (user is null)
 | 
				
			||||||
                    return;
 | 
					                    return;
 | 
				
			||||||
                ch = await user.GetOrCreateDMChannelAsync().ConfigureAwait(false);
 | 
					                ch = await user.CreateDMChannelAsync();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,7 +38,7 @@ public class StreamRoleService : INService
 | 
				
			|||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private Task Client_GuildMemberUpdated(SocketGuildUser before, SocketGuildUser after)
 | 
					    private Task Client_GuildMemberUpdated(Cacheable<SocketGuildUser, ulong> cacheable, SocketGuildUser after)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var _ = Task.Run(async () =>
 | 
					        var _ = Task.Run(async () =>
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -66,7 +66,7 @@ public partial class Utility : NadekoModule
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        var rng = new NadekoRandom();
 | 
					        var rng = new NadekoRandom();
 | 
				
			||||||
        var arr = await Task.Run(() => socketGuild.Users
 | 
					        var arr = await Task.Run(() => socketGuild.Users
 | 
				
			||||||
            .Where(u => u.Activity?.Name?.ToUpperInvariant() == game)
 | 
					            .Where(u => u.Activities.FirstOrDefault()?.Name?.ToUpperInvariant() == game)
 | 
				
			||||||
            .Select(u => u.Username)
 | 
					            .Select(u => u.Username)
 | 
				
			||||||
            .OrderBy(x => rng.Next())
 | 
					            .OrderBy(x => rng.Next())
 | 
				
			||||||
            .Take(60)
 | 
					            .Take(60)
 | 
				
			||||||
@@ -277,24 +277,24 @@ public partial class Utility : NadekoModule
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    [NadekoCommand, Aliases]
 | 
					    [NadekoCommand, Aliases]
 | 
				
			||||||
    [RequireContext(ContextType.Guild)]
 | 
					    [RequireContext(ContextType.Guild)]
 | 
				
			||||||
    [BotPerm(GuildPerm.ManageEmojis)]
 | 
					    [BotPerm(GuildPerm.ManageEmojisAndStickers)]
 | 
				
			||||||
    [UserPerm(GuildPerm.ManageEmojis)]
 | 
					    [UserPerm(GuildPerm.ManageEmojisAndStickers)]
 | 
				
			||||||
    [Priority(2)]
 | 
					    [Priority(2)]
 | 
				
			||||||
    public Task EmojiAdd(string name, Emote emote)
 | 
					    public Task EmojiAdd(string name, Emote emote)
 | 
				
			||||||
        => EmojiAdd(name, emote.Url);
 | 
					        => EmojiAdd(name, emote.Url);
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
    [NadekoCommand, Aliases]
 | 
					    [NadekoCommand, Aliases]
 | 
				
			||||||
    [RequireContext(ContextType.Guild)]
 | 
					    [RequireContext(ContextType.Guild)]
 | 
				
			||||||
    [BotPerm(GuildPerm.ManageEmojis)]
 | 
					    [BotPerm(GuildPerm.ManageEmojisAndStickers)]
 | 
				
			||||||
    [UserPerm(GuildPerm.ManageEmojis)]
 | 
					    [UserPerm(GuildPerm.ManageEmojisAndStickers)]
 | 
				
			||||||
    [Priority(1)]
 | 
					    [Priority(1)]
 | 
				
			||||||
    public Task EmojiAdd(Emote emote)
 | 
					    public Task EmojiAdd(Emote emote)
 | 
				
			||||||
        => EmojiAdd(emote.Name, emote.Url);
 | 
					        => EmojiAdd(emote.Name, emote.Url);
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
    [NadekoCommand, Aliases]
 | 
					    [NadekoCommand, Aliases]
 | 
				
			||||||
    [RequireContext(ContextType.Guild)]
 | 
					    [RequireContext(ContextType.Guild)]
 | 
				
			||||||
    [BotPerm(GuildPerm.ManageEmojis)]
 | 
					    [BotPerm(GuildPerm.ManageEmojisAndStickers)]
 | 
				
			||||||
    [UserPerm(GuildPerm.ManageEmojis)]
 | 
					    [UserPerm(GuildPerm.ManageEmojisAndStickers)]
 | 
				
			||||||
    [Priority(0)]
 | 
					    [Priority(0)]
 | 
				
			||||||
    public async Task EmojiAdd(string name, string url = null)
 | 
					    public async Task EmojiAdd(string name, string url = null)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -250,9 +250,7 @@ public class XpService : INService
 | 
				
			|||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        if (x.NotifyType == XpNotificationLocation.Dm)
 | 
					                        if (x.NotifyType == XpNotificationLocation.Dm)
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            var chan = await x.User.GetOrCreateDMChannelAsync();
 | 
					                                await x.User.SendConfirmAsync(_eb,
 | 
				
			||||||
                            if (chan != null)
 | 
					 | 
				
			||||||
                                await chan.SendConfirmAsync(_eb,
 | 
					 | 
				
			||||||
                                    _strings.GetText(strs.level_up_dm(
 | 
					                                    _strings.GetText(strs.level_up_dm(
 | 
				
			||||||
                                            x.User.Mention, Format.Bold(x.Level.ToString()),
 | 
					                                            x.User.Mention, Format.Bold(x.Level.ToString()),
 | 
				
			||||||
                                            Format.Bold(x.Guild.ToString() ?? "-")),
 | 
					                                            Format.Bold(x.Guild.ToString() ?? "-")),
 | 
				
			||||||
@@ -272,7 +270,7 @@ public class XpService : INService
 | 
				
			|||||||
                        IMessageChannel chan;
 | 
					                        IMessageChannel chan;
 | 
				
			||||||
                        if (x.NotifyType == XpNotificationLocation.Dm)
 | 
					                        if (x.NotifyType == XpNotificationLocation.Dm)
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            chan = await x.User.GetOrCreateDMChannelAsync();
 | 
					                            chan = await x.User.CreateDMChannelAsync();
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        else // channel
 | 
					                        else // channel
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,11 +12,11 @@
 | 
				
			|||||||
  
 | 
					  
 | 
				
			||||||
  <ItemGroup>
 | 
					  <ItemGroup>
 | 
				
			||||||
    <PackageReference Include="AngleSharp" Version="0.16.1" />
 | 
					    <PackageReference Include="AngleSharp" Version="0.16.1" />
 | 
				
			||||||
    <PackageReference Include="AWSSDK.S3" Version="3.7.7.3" />
 | 
					    <PackageReference Include="AWSSDK.S3" Version="3.7.7.5" />
 | 
				
			||||||
    <PackageReference Include="Cloneable" Version="1.3.0" />
 | 
					    <PackageReference Include="Cloneable" Version="1.3.0" />
 | 
				
			||||||
    <PackageReference Include="CodeHollow.FeedReader" Version="1.2.2" />
 | 
					    <PackageReference Include="CodeHollow.FeedReader" Version="1.2.2" />
 | 
				
			||||||
    <PackageReference Include="CommandLineParser" Version="2.8.0" />
 | 
					    <PackageReference Include="CommandLineParser" Version="2.8.0" />
 | 
				
			||||||
    <PackageReference Include="Discord.Net" Version="2.4.0" />
 | 
					    <PackageReference Include="Discord.Net" Version="3.0.0" />
 | 
				
			||||||
    <PackageReference Include="CoreCLR-NCalc" Version="2.2.92" />
 | 
					    <PackageReference Include="CoreCLR-NCalc" Version="2.2.92" />
 | 
				
			||||||
    <PackageReference Include="Google.Apis.Urlshortener.v1" Version="1.41.1.138" />
 | 
					    <PackageReference Include="Google.Apis.Urlshortener.v1" Version="1.41.1.138" />
 | 
				
			||||||
    <PackageReference Include="Google.Apis.YouTube.v3" Version="1.55.0.2449" />
 | 
					    <PackageReference Include="Google.Apis.YouTube.v3" Version="1.55.0.2449" />
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -355,7 +355,7 @@ public class CommandHandler : INService
 | 
				
			|||||||
        var chosenOverload = successfulParses[0];
 | 
					        var chosenOverload = successfulParses[0];
 | 
				
			||||||
        var execResult = (ExecuteResult)await chosenOverload.Key.ExecuteAsync(context, chosenOverload.Value, services).ConfigureAwait(false);
 | 
					        var execResult = (ExecuteResult)await chosenOverload.Key.ExecuteAsync(context, chosenOverload.Value, services).ConfigureAwait(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (execResult.Exception != null && (!(execResult.Exception is HttpException he) || he.DiscordCode != 50013))
 | 
					        if (execResult.Exception != null && (!(execResult.Exception is HttpException he) || he.DiscordCode != DiscordErrorCode.InsufficientPermissions))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Log.Warning(execResult.Exception, "Command Error");
 | 
					            Log.Warning(execResult.Exception, "Command Error");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,7 @@ public class GreetSettingsService : INService
 | 
				
			|||||||
    private readonly DiscordSocketClient _client;
 | 
					    private readonly DiscordSocketClient _client;
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
    private GreetGrouper<IGuildUser> greets = new GreetGrouper<IGuildUser>();
 | 
					    private GreetGrouper<IGuildUser> greets = new GreetGrouper<IGuildUser>();
 | 
				
			||||||
    private GreetGrouper<IGuildUser> byes = new GreetGrouper<IGuildUser>();
 | 
					    private GreetGrouper<IUser> byes = new GreetGrouper<IUser>();
 | 
				
			||||||
    private readonly BotConfigService _bss;
 | 
					    private readonly BotConfigService _bss;
 | 
				
			||||||
    private readonly IEmbedBuilderService _eb;
 | 
					    private readonly IEmbedBuilderService _eb;
 | 
				
			||||||
    public bool GroupGreets => _bss.Data.GroupGreets;
 | 
					    public bool GroupGreets => _bss.Data.GroupGreets;
 | 
				
			||||||
@@ -41,14 +41,15 @@ public class GreetSettingsService : INService
 | 
				
			|||||||
        _client.GuildMemberUpdated += ClientOnGuildMemberUpdated;
 | 
					        _client.GuildMemberUpdated += ClientOnGuildMemberUpdated;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private Task ClientOnGuildMemberUpdated(SocketGuildUser oldUser, SocketGuildUser newUser)
 | 
					    private Task ClientOnGuildMemberUpdated(Cacheable<SocketGuildUser, ulong> optOldUser, SocketGuildUser newUser)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        // if user is a new booster
 | 
					        // if user is a new booster
 | 
				
			||||||
        // or boosted again the same server
 | 
					        // or boosted again the same server
 | 
				
			||||||
        if (oldUser is { PremiumSince: null } && newUser is { PremiumSince: not null }
 | 
					        if ((optOldUser.Value is { PremiumSince: null }
 | 
				
			||||||
            || oldUser?.PremiumSince is { } oldDate 
 | 
					             && newUser is { PremiumSince: not null })
 | 
				
			||||||
 | 
					            || (optOldUser.Value?.PremiumSince is { } oldDate
 | 
				
			||||||
                && newUser?.PremiumSince is { } newDate
 | 
					                && newUser?.PremiumSince is { } newDate
 | 
				
			||||||
            && newDate > oldDate)
 | 
					                && newDate > oldDate))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var conf = GetOrAddSettingsForGuild(newUser.Guild.Id);
 | 
					            var conf = GetOrAddSettingsForGuild(newUser.Guild.Id);
 | 
				
			||||||
            if (!conf.SendBoostMessage) return Task.CompletedTask;
 | 
					            if (!conf.SendBoostMessage) return Task.CompletedTask;
 | 
				
			||||||
@@ -101,16 +102,16 @@ public class GreetSettingsService : INService
 | 
				
			|||||||
        return Task.CompletedTask;
 | 
					        return Task.CompletedTask;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private Task UserLeft(IGuildUser user)
 | 
					    private Task UserLeft(SocketGuild guild, SocketUser user)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var _ = Task.Run(async () =>
 | 
					        var _ = Task.Run(async () =>
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            try
 | 
					            try
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var conf = GetOrAddSettingsForGuild(user.GuildId);
 | 
					                var conf = GetOrAddSettingsForGuild(guild.Id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (!conf.SendChannelByeMessage) return;
 | 
					                if (!conf.SendChannelByeMessage) return;
 | 
				
			||||||
                var channel = (await user.Guild.GetTextChannelsAsync().ConfigureAwait(false)).SingleOrDefault(c => c.Id == conf.ByeMessageChannelId);
 | 
					                var channel = guild.TextChannels.FirstOrDefault(c => c.Id == conf.ByeMessageChannelId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (channel is null) //maybe warn the server owner that the channel is missing
 | 
					                if (channel is null) //maybe warn the server owner that the channel is missing
 | 
				
			||||||
                    return;
 | 
					                    return;
 | 
				
			||||||
@@ -120,7 +121,7 @@ public class GreetSettingsService : INService
 | 
				
			|||||||
                    // if group is newly created, greet that user right away,
 | 
					                    // if group is newly created, greet that user right away,
 | 
				
			||||||
                    // but any user which joins in the next 5 seconds will
 | 
					                    // but any user which joins in the next 5 seconds will
 | 
				
			||||||
                    // be greeted in a group greet
 | 
					                    // be greeted in a group greet
 | 
				
			||||||
                    if (byes.CreateOrAdd(user.GuildId, user))
 | 
					                    if (byes.CreateOrAdd(guild.Id, user))
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        // greet single user
 | 
					                        // greet single user
 | 
				
			||||||
                        await ByeUsers(conf, channel, new[] {user});
 | 
					                        await ByeUsers(conf, channel, new[] {user});
 | 
				
			||||||
@@ -128,7 +129,7 @@ public class GreetSettingsService : INService
 | 
				
			|||||||
                        while(!groupClear)
 | 
					                        while(!groupClear)
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            await Task.Delay(5000).ConfigureAwait(false);
 | 
					                            await Task.Delay(5000).ConfigureAwait(false);
 | 
				
			||||||
                            groupClear = byes.ClearGroup(user.GuildId, 5, out var toBye);
 | 
					                            groupClear = byes.ClearGroup(guild.Id, 5, out var toBye);
 | 
				
			||||||
                            await ByeUsers(conf, channel, toBye);
 | 
					                            await ByeUsers(conf, channel, toBye);
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
@@ -290,9 +291,9 @@ public class GreetSettingsService : INService
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                if (conf.SendDmGreetMessage)
 | 
					                if (conf.SendDmGreetMessage)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    var channel = await user.GetOrCreateDMChannelAsync().ConfigureAwait(false);
 | 
					                    var channel = await user.CreateDMChannelAsync();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if (channel != null)
 | 
					                    if (channel is not null)
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        await GreetDmUser(conf, channel, user);
 | 
					                        await GreetDmUser(conf, channel, user);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -75,7 +75,7 @@ public class CurrencyService : ICurrencyService, INService
 | 
				
			|||||||
            try
 | 
					            try
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var sign = _gss.Data.Currency.Sign;
 | 
					                var sign = _gss.Data.Currency.Sign;
 | 
				
			||||||
                await (await user.GetOrCreateDMChannelAsync())
 | 
					                await user
 | 
				
			||||||
                    .EmbedAsync(_eb.Create()
 | 
					                    .EmbedAsync(_eb.Create()
 | 
				
			||||||
                        .WithOkColor()
 | 
					                        .WithOkColor()
 | 
				
			||||||
                        .WithTitle($"Received Currency")
 | 
					                        .WithTitle($"Received Currency")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,23 +39,6 @@ public static class Extensions
 | 
				
			|||||||
            _ => throw new ArgumentOutOfRangeException(nameof(text))
 | 
					            _ => throw new ArgumentOutOfRangeException(nameof(text))
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static Task<IUserMessage> SendAsync(this IMessageChannel channel, string plainText, Embed embed, bool sanitizeAll = false)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        plainText = sanitizeAll
 | 
					 | 
				
			||||||
            ? plainText?.SanitizeAllMentions() ?? ""
 | 
					 | 
				
			||||||
            : plainText?.SanitizeMentions() ?? "";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return channel.SendMessageAsync(plainText, embed: embed);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
    public static Task<IUserMessage> SendAsync(this IMessageChannel channel, SmartText text, bool sanitizeAll = false)
 | 
					 | 
				
			||||||
        => text switch
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            SmartEmbedText set => channel.SendAsync(set.PlainText, set.GetEmbed().Build(), sanitizeAll),
 | 
					 | 
				
			||||||
            SmartPlainText st => channel.SendAsync(st.Text, null, sanitizeAll),
 | 
					 | 
				
			||||||
            _ => throw new ArgumentOutOfRangeException(nameof(text))
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public static List<ulong> GetGuildIds(this DiscordSocketClient client)
 | 
					    public static List<ulong> GetGuildIds(this DiscordSocketClient client)
 | 
				
			||||||
        => client.Guilds.Select(x => x.Id).ToList();
 | 
					        => client.Guilds.Select(x => x.Id).ToList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -334,10 +317,9 @@ public static class Extensions
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    public static async Task<IMessage> SendMessageToOwnerAsync(this IGuild guild, string message)
 | 
					    public static async Task<IMessage> SendMessageToOwnerAsync(this IGuild guild, string message)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var ownerPrivate = await (await guild.GetOwnerAsync().ConfigureAwait(false)).GetOrCreateDMChannelAsync()
 | 
					        var owner = await guild.GetOwnerAsync();
 | 
				
			||||||
            .ConfigureAwait(false);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return await ownerPrivate.SendMessageAsync(message).ConfigureAwait(false);
 | 
					        return await owner.SendMessageAsync(message);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static bool IsImage(this HttpResponseMessage msg) => IsImage(msg, out _);
 | 
					    public static bool IsImage(this HttpResponseMessage msg) => IsImage(msg, out _);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,23 @@ public static class IMessageChannelExtensions
 | 
				
			|||||||
        => ch.SendMessageAsync(msg, embed: embed.Build(),
 | 
					        => ch.SendMessageAsync(msg, embed: embed.Build(),
 | 
				
			||||||
            options: new() { RetryMode  = RetryMode.AlwaysRetry });
 | 
					            options: new() { RetryMode  = RetryMode.AlwaysRetry });
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
					    public static Task<IUserMessage> SendAsync(this IMessageChannel channel, string plainText, Embed embed, bool sanitizeAll = false)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        plainText = sanitizeAll
 | 
				
			||||||
 | 
					            ? plainText?.SanitizeAllMentions() ?? ""
 | 
				
			||||||
 | 
					            : plainText?.SanitizeMentions() ?? "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return channel.SendMessageAsync(plainText, embed: embed);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					    public static Task<IUserMessage> SendAsync(this IMessageChannel channel, SmartText text, bool sanitizeAll = false)
 | 
				
			||||||
 | 
					        => text switch
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            SmartEmbedText set => channel.SendAsync(set.PlainText, set.GetEmbed().Build(), sanitizeAll),
 | 
				
			||||||
 | 
					            SmartPlainText st => channel.SendAsync(st.Text, null, sanitizeAll),
 | 
				
			||||||
 | 
					            _ => throw new ArgumentOutOfRangeException(nameof(text))
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // this is a huge problem, because now i don't have
 | 
					    // this is a huge problem, because now i don't have
 | 
				
			||||||
    // access to embed builder service
 | 
					    // access to embed builder service
 | 
				
			||||||
    // as this is an extension of the message channel
 | 
					    // as this is an extension of the message channel
 | 
				
			||||||
@@ -97,7 +114,7 @@ public static class IMessageChannelExtensions
 | 
				
			|||||||
        else if (addPaginatedFooter)
 | 
					        else if (addPaginatedFooter)
 | 
				
			||||||
            embed.AddPaginatedFooter(currentPage, lastPage);
 | 
					            embed.AddPaginatedFooter(currentPage, lastPage);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        var msg = await ctx.Channel.EmbedAsync(embed).ConfigureAwait(false) as IUserMessage;
 | 
					        var msg = await ctx.Channel.EmbedAsync(embed).ConfigureAwait(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (lastPage == 0 || !canPaginate)
 | 
					        if (lastPage == 0 || !canPaginate)
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,8 +4,26 @@ namespace NadekoBot.Extensions;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
public static class IUserExtensions
 | 
					public static class IUserExtensions
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    public static async Task<IUserMessage> EmbedAsync(this IUser user, IEmbedBuilder embed, string msg = "")
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var ch = await user.CreateDMChannelAsync();
 | 
				
			||||||
 | 
					        return await ch.EmbedAsync(embed, msg);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    public static async Task<IUserMessage> SendAsync(this IUser user, string plainText, Embed embed, bool sanitizeAll = false)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var ch = await user.CreateDMChannelAsync();
 | 
				
			||||||
 | 
					        return await ch.SendAsync(plainText, embed, sanitizeAll);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static async Task<IUserMessage> SendAsync(this IUser user, SmartText text, bool sanitizeAll = false)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var ch = await user.CreateDMChannelAsync();
 | 
				
			||||||
 | 
					        return await ch.SendAsync(text, sanitizeAll);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    public static async Task<IUserMessage> SendConfirmAsync(this IUser user, IEmbedBuilderService eb, string text)
 | 
					    public static async Task<IUserMessage> SendConfirmAsync(this IUser user, IEmbedBuilderService eb, string text)
 | 
				
			||||||
        => await (await user.GetOrCreateDMChannelAsync()).SendMessageAsync("", embed: eb.Create()
 | 
					        => await user.SendMessageAsync("", embed: eb.Create()
 | 
				
			||||||
            .WithOkColor()
 | 
					            .WithOkColor()
 | 
				
			||||||
            .WithDescription(text)
 | 
					            .WithDescription(text)
 | 
				
			||||||
            .Build());
 | 
					            .Build());
 | 
				
			||||||
@@ -16,7 +34,7 @@ public static class IUserExtensions
 | 
				
			|||||||
        if (url != null && Uri.IsWellFormedUriString(url, UriKind.Absolute))
 | 
					        if (url != null && Uri.IsWellFormedUriString(url, UriKind.Absolute))
 | 
				
			||||||
            embed.WithUrl(url);
 | 
					            embed.WithUrl(url);
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
        return await (await user.GetOrCreateDMChannelAsync()).SendMessageAsync("", embed: embed.Build());
 | 
					        return await user.SendMessageAsync("", embed: embed.Build());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static async Task<IUserMessage> SendErrorAsync(this IUser user, IEmbedBuilderService eb, string title, string error, string url = null)
 | 
					    public static async Task<IUserMessage> SendErrorAsync(this IUser user, IEmbedBuilderService eb, string title, string error, string url = null)
 | 
				
			||||||
@@ -25,11 +43,11 @@ public static class IUserExtensions
 | 
				
			|||||||
        if (url != null && Uri.IsWellFormedUriString(url, UriKind.Absolute))
 | 
					        if (url != null && Uri.IsWellFormedUriString(url, UriKind.Absolute))
 | 
				
			||||||
            embed.WithUrl(url);
 | 
					            embed.WithUrl(url);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return await (await user.GetOrCreateDMChannelAsync().ConfigureAwait(false)).SendMessageAsync("", embed: embed.Build()).ConfigureAwait(false);
 | 
					        return await user.SendMessageAsync("", embed: embed.Build()).ConfigureAwait(false);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static async Task<IUserMessage> SendErrorAsync(this IUser user, IEmbedBuilderService eb, string error)
 | 
					    public static async Task<IUserMessage> SendErrorAsync(this IUser user, IEmbedBuilderService eb, string error)
 | 
				
			||||||
        => await (await user.GetOrCreateDMChannelAsync())
 | 
					        => await user
 | 
				
			||||||
            .SendMessageAsync("", embed: eb.Create()
 | 
					            .SendMessageAsync("", embed: eb.Create()
 | 
				
			||||||
                .WithErrorColor()
 | 
					                .WithErrorColor()
 | 
				
			||||||
                .WithDescription(error)
 | 
					                .WithDescription(error)
 | 
				
			||||||
@@ -39,12 +57,12 @@ public static class IUserExtensions
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        await using (var file = File.Open(filePath, FileMode.Open))
 | 
					        await using (var file = File.Open(filePath, FileMode.Open))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return await (await user.GetOrCreateDMChannelAsync().ConfigureAwait(false)).SendFileAsync(file, caption ?? "x", text, isTTS).ConfigureAwait(false);
 | 
					            return await user.SendFileAsync(file, caption ?? "x", text, isTTS).ConfigureAwait(false);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static async Task<IUserMessage> SendFileAsync(this IUser user, Stream fileStream, string fileName, string caption = null, bool isTTS = false) =>
 | 
					    public static async Task<IUserMessage> SendFileAsync(this IUser user, Stream fileStream, string fileName, string caption = null, bool isTTS = false) =>
 | 
				
			||||||
        await (await user.GetOrCreateDMChannelAsync().ConfigureAwait(false)).SendFileAsync(fileStream, fileName, caption, isTTS).ConfigureAwait(false);
 | 
					        await user.SendFileAsync(fileStream, fileName, caption, isTTS).ConfigureAwait(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // This method is used by everything that fetches the avatar from a user
 | 
					    // This method is used by everything that fetches the avatar from a user
 | 
				
			||||||
    public static Uri RealAvatarUrl(this IUser usr, ushort size = 128)
 | 
					    public static Uri RealAvatarUrl(this IUser usr, ushort size = 128)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user