mirror of
				https://gitlab.com/Kwoth/nadekobot.git
				synced 2025-11-04 00:34:26 -05:00 
			
		
		
		
	Implemented .linkonly (as an alternative to .imageonly). Updated pokaman with latest generations. Updated responses, fixed some warnings
This commit is contained in:
		@@ -5,4 +5,11 @@ public class ImageOnlyChannel : DbEntity
 | 
			
		||||
{
 | 
			
		||||
    public ulong GuildId { get; set; }
 | 
			
		||||
    public ulong ChannelId { get; set; }
 | 
			
		||||
    public OnlyChannelType Type { get; set; }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public enum OnlyChannelType
 | 
			
		||||
{
 | 
			
		||||
    Image,
 | 
			
		||||
    Link
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
using NadekoBot.Services.Database.Models;
 | 
			
		||||
#nullable disable warnings
 | 
			
		||||
using NadekoBot.Services.Database.Models;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Db.Models;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2858
									
								
								src/NadekoBot/Migrations/Sqlite/20220727005807_linkonly-channels.Designer.cs
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										2858
									
								
								src/NadekoBot/Migrations/Sqlite/20220727005807_linkonly-channels.Designer.cs
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
using Microsoft.EntityFrameworkCore.Migrations;
 | 
			
		||||
 | 
			
		||||
#nullable disable
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Migrations
 | 
			
		||||
{
 | 
			
		||||
    public partial class linkonlychannels : Migration
 | 
			
		||||
    {
 | 
			
		||||
        protected override void Up(MigrationBuilder migrationBuilder)
 | 
			
		||||
        {
 | 
			
		||||
            migrationBuilder.AddColumn<int>(
 | 
			
		||||
                name: "Type",
 | 
			
		||||
                table: "ImageOnlyChannels",
 | 
			
		||||
                type: "INTEGER",
 | 
			
		||||
                nullable: false,
 | 
			
		||||
                defaultValue: 0);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override void Down(MigrationBuilder migrationBuilder)
 | 
			
		||||
        {
 | 
			
		||||
            migrationBuilder.DropColumn(
 | 
			
		||||
                name: "Type",
 | 
			
		||||
                table: "ImageOnlyChannels");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1088,6 +1088,9 @@ namespace NadekoBot.Migrations
 | 
			
		||||
                    b.Property<ulong>("GuildId")
 | 
			
		||||
                        .HasColumnType("INTEGER");
 | 
			
		||||
 | 
			
		||||
                    b.Property<int>("Type")
 | 
			
		||||
                        .HasColumnType("INTEGER");
 | 
			
		||||
 | 
			
		||||
                    b.HasKey("Id");
 | 
			
		||||
 | 
			
		||||
                    b.HasIndex("ChannelId")
 | 
			
		||||
 
 | 
			
		||||
@@ -32,10 +32,10 @@ public partial class Administration : NadekoModule<AdministrationService>
 | 
			
		||||
        Inherit
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private readonly ImageOnlyChannelService _imageOnly;
 | 
			
		||||
    private readonly SomethingOnlyChannelService _somethingOnly;
 | 
			
		||||
 | 
			
		||||
    public Administration(ImageOnlyChannelService imageOnly)
 | 
			
		||||
        => _imageOnly = imageOnly;
 | 
			
		||||
    public Administration(SomethingOnlyChannelService somethingOnly)
 | 
			
		||||
        => _somethingOnly = somethingOnly;
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
    [RequireContext(ContextType.Guild)]
 | 
			
		||||
@@ -43,12 +43,25 @@ public partial class Administration : NadekoModule<AdministrationService>
 | 
			
		||||
    [BotPerm(GuildPerm.ManageGuild)]
 | 
			
		||||
    public async Task ImageOnlyChannel(StoopidTime time = null)
 | 
			
		||||
    {
 | 
			
		||||
        var newValue = _imageOnly.ToggleImageOnlyChannel(ctx.Guild.Id, ctx.Channel.Id);
 | 
			
		||||
        var newValue = await _somethingOnly.ToggleImageOnlyChannelAsync(ctx.Guild.Id, ctx.Channel.Id);
 | 
			
		||||
        if (newValue)
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.imageonly_enable);
 | 
			
		||||
        else
 | 
			
		||||
            await ReplyPendingLocalizedAsync(strs.imageonly_disable);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    [Cmd]
 | 
			
		||||
    [RequireContext(ContextType.Guild)]
 | 
			
		||||
    [UserPerm(GuildPerm.Administrator)]
 | 
			
		||||
    [BotPerm(GuildPerm.ManageGuild)]
 | 
			
		||||
    public async Task LinkOnlyChannel(StoopidTime time = null)
 | 
			
		||||
    {
 | 
			
		||||
        var newValue = await _somethingOnly.ToggleLinkOnlyChannelAsync(ctx.Guild.Id, ctx.Channel.Id);
 | 
			
		||||
        if (newValue)
 | 
			
		||||
            await ReplyConfirmLocalizedAsync(strs.linkonly_enable);
 | 
			
		||||
        else
 | 
			
		||||
            await ReplyPendingLocalizedAsync(strs.linkonly_disable);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [Cmd]
 | 
			
		||||
    [RequireContext(ContextType.Guild)]
 | 
			
		||||
 
 | 
			
		||||
@@ -5,16 +5,18 @@ using NadekoBot.Common.ModuleBehaviors;
 | 
			
		||||
using System.Net;
 | 
			
		||||
using System.Threading.Channels;
 | 
			
		||||
using Nadeko.Common;
 | 
			
		||||
using NadekoBot.Services.Database.Models;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Modules.Administration.Services;
 | 
			
		||||
 | 
			
		||||
public sealed class ImageOnlyChannelService : IExecOnMessage
 | 
			
		||||
public sealed class SomethingOnlyChannelService : IExecOnMessage
 | 
			
		||||
{
 | 
			
		||||
    public int Priority { get; } = 0;
 | 
			
		||||
    private readonly IMemoryCache _ticketCache;
 | 
			
		||||
    private readonly DiscordSocketClient _client;
 | 
			
		||||
    private readonly DbService _db;
 | 
			
		||||
    private readonly ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>> _enabledOn;
 | 
			
		||||
    private readonly ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>> _imageOnly;
 | 
			
		||||
    private readonly ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>> _linkOnly;
 | 
			
		||||
 | 
			
		||||
    private readonly Channel<IUserMessage> _deleteQueue = Channel.CreateBounded<IUserMessage>(
 | 
			
		||||
        new BoundedChannelOptions(100)
 | 
			
		||||
@@ -25,32 +27,39 @@ public sealed class ImageOnlyChannelService : IExecOnMessage
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public ImageOnlyChannelService(IMemoryCache ticketCache, DiscordSocketClient client, DbService db)
 | 
			
		||||
    public SomethingOnlyChannelService(IMemoryCache ticketCache, DiscordSocketClient client, DbService db)
 | 
			
		||||
    {
 | 
			
		||||
        _ticketCache = ticketCache;
 | 
			
		||||
        _client = client;
 | 
			
		||||
        _db = db;
 | 
			
		||||
 | 
			
		||||
        using var uow = _db.GetDbContext();
 | 
			
		||||
        _enabledOn = uow.ImageOnlyChannels.ToList()
 | 
			
		||||
        _imageOnly = uow.ImageOnlyChannels
 | 
			
		||||
            .Where(x => x.Type == OnlyChannelType.Image)
 | 
			
		||||
                        .ToList()
 | 
			
		||||
                        .GroupBy(x => x.GuildId)
 | 
			
		||||
                        .ToDictionary(x => x.Key, x => new ConcurrentHashSet<ulong>(x.Select(y => y.ChannelId)))
 | 
			
		||||
                        .ToConcurrent();
 | 
			
		||||
 | 
			
		||||
        _linkOnly = uow.ImageOnlyChannels
 | 
			
		||||
            .Where(x => x.Type == OnlyChannelType.Link)
 | 
			
		||||
            .ToList()
 | 
			
		||||
            .GroupBy(x => x.GuildId)
 | 
			
		||||
            .ToDictionary(x => x.Key, x => new ConcurrentHashSet<ulong>(x.Select(y => y.ChannelId)))
 | 
			
		||||
            .ToConcurrent();
 | 
			
		||||
        
 | 
			
		||||
        _ = Task.Run(DeleteQueueRunner);
 | 
			
		||||
 | 
			
		||||
        _client.ChannelDestroyed += ClientOnChannelDestroyed;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Task ClientOnChannelDestroyed(SocketChannel ch)
 | 
			
		||||
    private async Task ClientOnChannelDestroyed(SocketChannel ch)
 | 
			
		||||
    {
 | 
			
		||||
        if (ch is not IGuildChannel gch)
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (_enabledOn.TryGetValue(gch.GuildId, out var channels) && channels.TryRemove(ch.Id))
 | 
			
		||||
            ToggleImageOnlyChannel(gch.GuildId, ch.Id, true);
 | 
			
		||||
 | 
			
		||||
        return Task.CompletedTask;
 | 
			
		||||
        if (_imageOnly.TryGetValue(gch.GuildId, out var channels) && channels.TryRemove(ch.Id))
 | 
			
		||||
            await ToggleImageOnlyChannelAsync(gch.GuildId, ch.Id, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private async Task DeleteQueueRunner()
 | 
			
		||||
@@ -66,31 +75,68 @@ public sealed class ImageOnlyChannelService : IExecOnMessage
 | 
			
		||||
            catch (HttpException ex) when (ex.HttpCode == HttpStatusCode.Forbidden)
 | 
			
		||||
            {
 | 
			
		||||
                // disable if bot can't delete messages in the channel
 | 
			
		||||
                ToggleImageOnlyChannel(((ITextChannel)toDelete.Channel).GuildId, toDelete.Channel.Id, true);
 | 
			
		||||
                await ToggleImageOnlyChannelAsync(((ITextChannel)toDelete.Channel).GuildId, toDelete.Channel.Id, true);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool ToggleImageOnlyChannel(ulong guildId, ulong channelId, bool forceDisable = false)
 | 
			
		||||
    public async Task<bool> ToggleImageOnlyChannelAsync(ulong guildId, ulong channelId, bool forceDisable = false)
 | 
			
		||||
    {
 | 
			
		||||
        var newState = false;
 | 
			
		||||
        using var uow = _db.GetDbContext();
 | 
			
		||||
        if (forceDisable || (_enabledOn.TryGetValue(guildId, out var channels) && channels.TryRemove(channelId)))
 | 
			
		||||
            uow.ImageOnlyChannels.Delete(x => x.ChannelId == channelId);
 | 
			
		||||
        await using var uow = _db.GetDbContext();
 | 
			
		||||
        if (forceDisable || (_imageOnly.TryGetValue(guildId, out var channels) && channels.TryRemove(channelId)))
 | 
			
		||||
        {
 | 
			
		||||
            await uow.ImageOnlyChannels.DeleteAsync(x => x.ChannelId == channelId && x.Type == OnlyChannelType.Link);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            await uow.ImageOnlyChannels.DeleteAsync(x => x.ChannelId == channelId);
 | 
			
		||||
            uow.ImageOnlyChannels.Add(new()
 | 
			
		||||
            {
 | 
			
		||||
                GuildId = guildId,
 | 
			
		||||
                ChannelId = channelId
 | 
			
		||||
                ChannelId = channelId,
 | 
			
		||||
                Type = OnlyChannelType.Image
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            channels = _enabledOn.GetOrAdd(guildId, new ConcurrentHashSet<ulong>());
 | 
			
		||||
            if (_linkOnly.TryGetValue(guildId, out var chs))
 | 
			
		||||
                chs.TryRemove(channelId);
 | 
			
		||||
            
 | 
			
		||||
            channels = _imageOnly.GetOrAdd(guildId, new ConcurrentHashSet<ulong>());
 | 
			
		||||
            channels.Add(channelId);
 | 
			
		||||
            newState = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        uow.SaveChanges();
 | 
			
		||||
        await uow.SaveChangesAsync();
 | 
			
		||||
        return newState;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public async Task<bool> ToggleLinkOnlyChannelAsync(ulong guildId, ulong channelId, bool forceDisable = false)
 | 
			
		||||
    {
 | 
			
		||||
        var newState = false;
 | 
			
		||||
        await using var uow = _db.GetDbContext();
 | 
			
		||||
        if (forceDisable || (_linkOnly.TryGetValue(guildId, out var channels) && channels.TryRemove(channelId)))
 | 
			
		||||
        {
 | 
			
		||||
            await uow.ImageOnlyChannels.DeleteAsync(x => x.ChannelId == channelId && x.Type == OnlyChannelType.Link);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            await uow.ImageOnlyChannels.DeleteAsync(x => x.ChannelId == channelId);
 | 
			
		||||
            uow.ImageOnlyChannels.Add(new()
 | 
			
		||||
            {
 | 
			
		||||
                GuildId = guildId,
 | 
			
		||||
                ChannelId = channelId,
 | 
			
		||||
                Type = OnlyChannelType.Link
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            if (_imageOnly.TryGetValue(guildId, out var chs))
 | 
			
		||||
                chs.TryRemove(channelId);
 | 
			
		||||
            
 | 
			
		||||
            channels = _linkOnly.GetOrAdd(guildId, new ConcurrentHashSet<ulong>());
 | 
			
		||||
            channels.Add(channelId);
 | 
			
		||||
            newState = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await uow.SaveChangesAsync();
 | 
			
		||||
        return newState;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -99,12 +145,28 @@ public sealed class ImageOnlyChannelService : IExecOnMessage
 | 
			
		||||
        if (msg.Channel is not ITextChannel tch)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        if (msg.Attachments.Any(x => x is { Height: > 0, Width: > 0 }))
 | 
			
		||||
            return false;
 | 
			
		||||
        if (_imageOnly.TryGetValue(tch.GuildId, out var chs) && chs.Contains(msg.Channel.Id))
 | 
			
		||||
            return await HandleOnlyChannel(tch, msg, OnlyChannelType.Image);
 | 
			
		||||
        
 | 
			
		||||
        if (_linkOnly.TryGetValue(tch.GuildId, out chs) && chs.Contains(msg.Channel.Id))
 | 
			
		||||
            return await HandleOnlyChannel(tch, msg, OnlyChannelType.Link);
 | 
			
		||||
 | 
			
		||||
        if (!_enabledOn.TryGetValue(tch.GuildId, out var chs) || !chs.Contains(msg.Channel.Id))
 | 
			
		||||
            return false;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private async Task<bool> HandleOnlyChannel(ITextChannel tch, IUserMessage msg, OnlyChannelType type)
 | 
			
		||||
    {
 | 
			
		||||
        if (type == OnlyChannelType.Image)
 | 
			
		||||
        {
 | 
			
		||||
            if (msg.Attachments.Any(x => x is { Height: > 0, Width: > 0 }))
 | 
			
		||||
                return false;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            if (msg.Content.TryGetUrlPath(out _))
 | 
			
		||||
                return false;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        var user = await tch.Guild.GetUserAsync(msg.Author.Id)
 | 
			
		||||
                   ?? await _client.Rest.GetGuildUserAsync(tch.GuildId, msg.Author.Id);
 | 
			
		||||
 | 
			
		||||
@@ -114,7 +176,7 @@ public sealed class ImageOnlyChannelService : IExecOnMessage
 | 
			
		||||
        // ignore owner and admin
 | 
			
		||||
        if (user.Id == tch.Guild.OwnerId || user.GuildPermissions.Administrator)
 | 
			
		||||
        {
 | 
			
		||||
            Log.Information("Image-Only: Ignoring owner od admin ({ChannelId})", msg.Channel.Id);
 | 
			
		||||
            Log.Information("{Type}-Only Channel: Ignoring owner od admin ({ChannelId})", type, msg.Channel.Id);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -125,7 +187,11 @@ public sealed class ImageOnlyChannelService : IExecOnMessage
 | 
			
		||||
 | 
			
		||||
        if (!botUser.GetPermissions(tch).ManageChannel)
 | 
			
		||||
        {
 | 
			
		||||
            ToggleImageOnlyChannel(tch.GuildId, tch.Id, true);
 | 
			
		||||
            if(type == OnlyChannelType.Image)
 | 
			
		||||
                await ToggleImageOnlyChannelAsync(tch.GuildId, tch.Id, true);
 | 
			
		||||
            else
 | 
			
		||||
                await ToggleImageOnlyChannelAsync(tch.GuildId, tch.Id, true);
 | 
			
		||||
            
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -133,7 +199,8 @@ public sealed class ImageOnlyChannelService : IExecOnMessage
 | 
			
		||||
        if (shouldLock)
 | 
			
		||||
        {
 | 
			
		||||
            await tch.AddPermissionOverwriteAsync(msg.Author, new(sendMessages: PermValue.Deny));
 | 
			
		||||
            Log.Warning("Image-Only: User {User} [{UserId}] has been banned from typing in the channel [{ChannelId}]",
 | 
			
		||||
            Log.Warning("{Type}-Only Channel: User {User} [{UserId}] has been banned from typing in the channel [{ChannelId}]",
 | 
			
		||||
                type,
 | 
			
		||||
                msg.Author,
 | 
			
		||||
                msg.Author.Id,
 | 
			
		||||
                msg.Channel.Id);
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ namespace NadekoBot.Modules.Games.Common.Trivia;
 | 
			
		||||
 | 
			
		||||
public sealed class PokemonQuestionPool : IQuestionPool
 | 
			
		||||
{
 | 
			
		||||
    public int QuestionsCount => 721; // xd
 | 
			
		||||
    public int QuestionsCount => 905; // xd
 | 
			
		||||
    private readonly NadekoRandom _rng;
 | 
			
		||||
    private readonly ILocalDataCache _cache;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,4 @@
 | 
			
		||||
#nullable disable warnings
 | 
			
		||||
using LinqToDB;
 | 
			
		||||
using Microsoft.EntityFrameworkCore;
 | 
			
		||||
using NadekoBot.Common.ModuleBehaviors;
 | 
			
		||||
@@ -391,9 +392,9 @@ public class XpService : INService, IReadyExecutor, IExecNoCommand
 | 
			
		||||
 | 
			
		||||
            template = JsonConvert.DeserializeObject<XpTemplate>(
 | 
			
		||||
                File.ReadAllText(XP_TEMPLATE_PATH),
 | 
			
		||||
                settings);
 | 
			
		||||
                settings)!;
 | 
			
		||||
 | 
			
		||||
            if (template!.Version < 1)
 | 
			
		||||
            if (template.Version < 1)
 | 
			
		||||
            {
 | 
			
		||||
                Log.Warning("Loaded default xp_template.json values as the old one was version 0. "
 | 
			
		||||
                            + "Old one was renamed to xp_template.json.old");
 | 
			
		||||
 
 | 
			
		||||
@@ -1219,6 +1219,10 @@ imageonlychannel:
 | 
			
		||||
  - imageonlychannel
 | 
			
		||||
  - imageonly
 | 
			
		||||
  - imagesonly
 | 
			
		||||
linkonlychannel:
 | 
			
		||||
  - linkonlychannel
 | 
			
		||||
  - linkonly
 | 
			
		||||
  - linkssonly
 | 
			
		||||
coordreload:
 | 
			
		||||
  - coordreload
 | 
			
		||||
quotesexport:
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@@ -2166,7 +2166,7 @@ imageonlychannel:
 | 
			
		||||
    Users who send more than a few non-image messages will be banned from using the channel. 
 | 
			
		||||
  args:
 | 
			
		||||
    - ""
 | 
			
		||||
linksonlychannel:
 | 
			
		||||
linkonlychannel:
 | 
			
		||||
  desc: |-
 | 
			
		||||
    Toggles whether the channel only allows links.
 | 
			
		||||
    Users who send more than a few non-link messages will be banned from using the channel. 
 | 
			
		||||
 
 | 
			
		||||
@@ -971,7 +971,9 @@
 | 
			
		||||
  "favorites": "Favorites",
 | 
			
		||||
  "tags": "Tags",
 | 
			
		||||
  "imageonly_enable": "This channel is now image-only.",
 | 
			
		||||
  "linkonly_enable": "This channel is now link-only.",
 | 
			
		||||
  "imageonly_disable": "This channel is no longer image-only.",
 | 
			
		||||
  "linkonly_disable": "This channel is no longer link-only.",
 | 
			
		||||
  "deleted_x_servers": "Deleted {0} servers.",
 | 
			
		||||
  "curtr_gift": "Gift from {0} [{1}]",
 | 
			
		||||
  "curtr_award": "Awarded by bot owner {0} [{1}]",  
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user