mirror of
				https://gitlab.com/Kwoth/nadekobot.git
				synced 2025-11-04 08:34:27 -05:00 
			
		
		
		
	NadekoBot Patronage system, Search commands improvements + fixes
This commit is contained in:
		@@ -0,0 +1,11 @@
 | 
			
		||||
#nullable disable
 | 
			
		||||
namespace NadekoBot.Common;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Classed marked with this attribute will not be added to the service provider 
 | 
			
		||||
/// </summary>
 | 
			
		||||
[AttributeUsage(AttributeTargets.Class)]
 | 
			
		||||
public class DontAddToIocContainerAttribute : Attribute
 | 
			
		||||
{
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
@@ -20,11 +20,19 @@ public sealed class NoPublicBotAttribute : PreconditionAttribute
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Classed marked with this attribute will not be added to the service provider 
 | 
			
		||||
/// </summary>
 | 
			
		||||
[AttributeUsage(AttributeTargets.Class)]
 | 
			
		||||
public class DontAddToIocContainerAttribute : Attribute
 | 
			
		||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
 | 
			
		||||
[SuppressMessage("Style", "IDE0022:Use expression body for methods")]
 | 
			
		||||
public sealed class OnlyPublicBotAttribute : PreconditionAttribute
 | 
			
		||||
{
 | 
			
		||||
    
 | 
			
		||||
    public override Task<PreconditionResult> CheckPermissionsAsync(
 | 
			
		||||
        ICommandContext context,
 | 
			
		||||
        CommandInfo command,
 | 
			
		||||
        IServiceProvider services)
 | 
			
		||||
    {
 | 
			
		||||
#if GLOBAL_NADEKO || DEBUG
 | 
			
		||||
        return Task.FromResult(PreconditionResult.FromSuccess());
 | 
			
		||||
#else
 | 
			
		||||
        return Task.FromResult(PreconditionResult.FromError("Only available on the public bot."));
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -18,7 +18,7 @@ public sealed class Creds : IBotCredentials
 | 
			
		||||
    [Comment("Keep this on 'true' unless you're sure your bot shouldn't use privileged intents or you're waiting to be accepted")]
 | 
			
		||||
    public bool UsePrivilegedIntents { get; set; }
 | 
			
		||||
 | 
			
		||||
    [Comment(@"The number of shards that the bot will running on.
 | 
			
		||||
    [Comment(@"The number of shards that the bot will be running on.
 | 
			
		||||
Leave at 1 if you don't know what you're doing.")]
 | 
			
		||||
    public int TotalShards { get; set; }
 | 
			
		||||
 | 
			
		||||
@@ -27,6 +27,16 @@ Leave at 1 if you don't know what you're doing.")]
 | 
			
		||||
Then, go to APIs and Services -> Credentials and click Create credentials -> API key.
 | 
			
		||||
Used only for Youtube Data Api (at the moment).")]
 | 
			
		||||
    public string GoogleApiKey { get; set; }
 | 
			
		||||
    
 | 
			
		||||
    [Comment(   
 | 
			
		||||
        @"Create a new custom search here https://programmablesearchengine.google.com/cse/create/new
 | 
			
		||||
Enable SafeSearch
 | 
			
		||||
Remove all Sites to Search
 | 
			
		||||
Enable Search the entire web
 | 
			
		||||
Copy the 'Search Engine ID' to the SearchId field
 | 
			
		||||
 | 
			
		||||
Do all steps again but enable image search for the ImageSearchId")]
 | 
			
		||||
    public GoogleApiConfig Google { get; set; }
 | 
			
		||||
 | 
			
		||||
    [Comment(@"Settings for voting system for discordbots. Meant for use on global Nadeko.")]
 | 
			
		||||
    public VotesSettings Votes { get; set; }
 | 
			
		||||
@@ -119,6 +129,7 @@ Windows default
 | 
			
		||||
        CoordinatorUrl = "http://localhost:3442";
 | 
			
		||||
 | 
			
		||||
        RestartCommand = new();
 | 
			
		||||
        Google = new();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -200,4 +211,10 @@ This should be equivalent to the DiscordsKey in your NadekoBot.Votes api appsett
 | 
			
		||||
            DiscordsKey = discordsKey;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public class GoogleApiConfig
 | 
			
		||||
{
 | 
			
		||||
    public string SearchId { get; init; }
 | 
			
		||||
    public string ImageSearchId { get; init; }
 | 
			
		||||
}
 | 
			
		||||
@@ -25,6 +25,7 @@ public interface IBotCredentials
 | 
			
		||||
    string CoordinatorUrl { get; set; }
 | 
			
		||||
    string TwitchClientId { get; set; }
 | 
			
		||||
    string TwitchClientSecret { get; set; }
 | 
			
		||||
    GoogleApiConfig Google { get; set; }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public class RestartConfig
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,11 @@
 | 
			
		||||
namespace NadekoBot;
 | 
			
		||||
 | 
			
		||||
public sealed class NadekoActionInteraction : NadekoOwnInteraction
 | 
			
		||||
public sealed class NadekoButtonActionInteraction : NadekoButtonOwnInteraction
 | 
			
		||||
{
 | 
			
		||||
    private readonly NadekoInteractionData _data;
 | 
			
		||||
    private readonly Func<SocketMessageComponent, Task> _action;
 | 
			
		||||
 | 
			
		||||
    public NadekoActionInteraction(
 | 
			
		||||
    public NadekoButtonActionInteraction(
 | 
			
		||||
        DiscordSocketClient client,
 | 
			
		||||
        ulong authorId,
 | 
			
		||||
        NadekoInteractionData data,
 | 
			
		||||
@@ -17,10 +17,12 @@ public sealed class NadekoActionInteraction : NadekoOwnInteraction
 | 
			
		||||
        _action = action;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public override string Name
 | 
			
		||||
    protected override string Name
 | 
			
		||||
        => _data.CustomId;
 | 
			
		||||
    public override IEmote Emote
 | 
			
		||||
    protected override IEmote Emote
 | 
			
		||||
        => _data.Emote;
 | 
			
		||||
    protected override string? Text
 | 
			
		||||
        => _data.Text;
 | 
			
		||||
 | 
			
		||||
    public override Task ExecuteOnActionAsync(SocketMessageComponent smc)
 | 
			
		||||
        => _action(smc);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,23 +1,24 @@
 | 
			
		||||
namespace NadekoBot;
 | 
			
		||||
 | 
			
		||||
public abstract class NadekoInteraction
 | 
			
		||||
public abstract class NadekoButtonInteraction
 | 
			
		||||
{
 | 
			
		||||
    // improvements:
 | 
			
		||||
    //  - state in OnAction
 | 
			
		||||
    //  - configurable delay
 | 
			
		||||
    //  - 
 | 
			
		||||
    public abstract string Name { get; }
 | 
			
		||||
    public abstract IEmote Emote { get; }
 | 
			
		||||
    protected abstract string Name { get; }
 | 
			
		||||
    protected abstract IEmote Emote { get; }
 | 
			
		||||
    protected virtual string? Text { get; } = null;
 | 
			
		||||
 | 
			
		||||
    protected readonly DiscordSocketClient _client;
 | 
			
		||||
    public DiscordSocketClient Client { get; }
 | 
			
		||||
 | 
			
		||||
    protected readonly TaskCompletionSource<bool> _interactionCompletedSource;
 | 
			
		||||
 | 
			
		||||
    protected IUserMessage message = null!;
 | 
			
		||||
 | 
			
		||||
    protected NadekoInteraction(DiscordSocketClient client)
 | 
			
		||||
    protected NadekoButtonInteraction(DiscordSocketClient client)
 | 
			
		||||
    {
 | 
			
		||||
        _client = client;
 | 
			
		||||
        Client = client;
 | 
			
		||||
        _interactionCompletedSource = new(TaskCreationOptions.RunContinuationsAsynchronously);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -25,9 +26,9 @@ public abstract class NadekoInteraction
 | 
			
		||||
    {
 | 
			
		||||
        message = msg;
 | 
			
		||||
 | 
			
		||||
        _client.InteractionCreated += OnInteraction;
 | 
			
		||||
        Client.InteractionCreated += OnInteraction;
 | 
			
		||||
        await Task.WhenAny(Task.Delay(10_000), _interactionCompletedSource.Task);
 | 
			
		||||
        _client.InteractionCreated -= OnInteraction;
 | 
			
		||||
        Client.InteractionCreated -= OnInteraction;
 | 
			
		||||
 | 
			
		||||
        await msg.ModifyAsync(m => m.Components = new ComponentBuilder().Build());
 | 
			
		||||
    }
 | 
			
		||||
@@ -65,13 +66,18 @@ public abstract class NadekoInteraction
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public MessageComponent CreateComponent()
 | 
			
		||||
    public virtual MessageComponent CreateComponent()
 | 
			
		||||
    {
 | 
			
		||||
        var comp = new ComponentBuilder()
 | 
			
		||||
            .WithButton(new ButtonBuilder(style: ButtonStyle.Secondary, emote: Emote, customId: Name));
 | 
			
		||||
            .WithButton(GetButtonBuilder());
 | 
			
		||||
 | 
			
		||||
        return comp.Build();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ButtonBuilder GetButtonBuilder()
 | 
			
		||||
        => new ButtonBuilder(style: ButtonStyle.Secondary, emote: Emote, customId: Name, label: Text);
 | 
			
		||||
 | 
			
		||||
    public abstract Task ExecuteOnActionAsync(SocketMessageComponent smc);
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// this is all so wrong ...
 | 
			
		||||
							
								
								
									
										43
									
								
								src/NadekoBot/Common/Interaction/NadekoInteractionArray.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/NadekoBot/Common/Interaction/NadekoInteractionArray.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
// namespace NadekoBot;
 | 
			
		||||
//
 | 
			
		||||
// public class NadekoButtonInteractionArray : NadekoButtonInteraction
 | 
			
		||||
// {
 | 
			
		||||
//     private readonly ButtonBuilder[] _bbs;
 | 
			
		||||
//     private readonly NadekoButtonInteraction[] _inters;
 | 
			
		||||
//
 | 
			
		||||
//     public NadekoButtonInteractionArray(params NadekoButtonInteraction[] inters)
 | 
			
		||||
//         : base(inters[0].Client)
 | 
			
		||||
//     {
 | 
			
		||||
//         _inters = inters;
 | 
			
		||||
//         _bbs = inters.Map(x => x.GetButtonBuilder());
 | 
			
		||||
//     }
 | 
			
		||||
//
 | 
			
		||||
//     protected override string Name
 | 
			
		||||
//         => throw new NotSupportedException();
 | 
			
		||||
//     protected override IEmote Emote
 | 
			
		||||
//         => throw new NotSupportedException();
 | 
			
		||||
//
 | 
			
		||||
//     protected override ValueTask<bool> Validate(SocketMessageComponent smc)
 | 
			
		||||
//         => new(true);
 | 
			
		||||
//
 | 
			
		||||
//     public override Task ExecuteOnActionAsync(SocketMessageComponent smc)
 | 
			
		||||
//     {
 | 
			
		||||
//         for (var i = 0; i < _bbs.Length; i++)
 | 
			
		||||
//         {
 | 
			
		||||
//             if (_bbs[i].CustomId == smc.Data.CustomId)
 | 
			
		||||
//                 return _inters[i].ExecuteOnActionAsync(smc);
 | 
			
		||||
//         }
 | 
			
		||||
//
 | 
			
		||||
//         return Task.CompletedTask;
 | 
			
		||||
//     }
 | 
			
		||||
//
 | 
			
		||||
//     public override MessageComponent CreateComponent()
 | 
			
		||||
//     {
 | 
			
		||||
//         var comp = new ComponentBuilder();
 | 
			
		||||
//
 | 
			
		||||
//         foreach (var bb in _bbs)
 | 
			
		||||
//             comp.WithButton(bb);
 | 
			
		||||
//         
 | 
			
		||||
//         return comp.Build();
 | 
			
		||||
//     }
 | 
			
		||||
// }
 | 
			
		||||
@@ -20,6 +20,7 @@ public class NadekoInteractionBuilder
 | 
			
		||||
    // {
 | 
			
		||||
    //     this.isOwn = isOwn;
 | 
			
		||||
    //     return this;
 | 
			
		||||
    
 | 
			
		||||
    // }
 | 
			
		||||
    
 | 
			
		||||
    public NadekoInteractionBuilder WithAction(in Func<SocketMessageComponent, Task> fn)
 | 
			
		||||
@@ -28,7 +29,7 @@ public class NadekoInteractionBuilder
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public NadekoActionInteraction Build(DiscordSocketClient client, ulong userId)
 | 
			
		||||
    public NadekoButtonActionInteraction Build(DiscordSocketClient client, ulong userId)
 | 
			
		||||
    {
 | 
			
		||||
        if (iData is null)
 | 
			
		||||
            throw new InvalidOperationException("You have to specify the data before building the interaction");
 | 
			
		||||
 
 | 
			
		||||
@@ -5,4 +5,4 @@
 | 
			
		||||
/// </summary>
 | 
			
		||||
/// <param name="Emote">Emote which will show on a button</param>
 | 
			
		||||
/// <param name="CustomId">Custom interaction id</param>
 | 
			
		||||
public record NadekoInteractionData(IEmote Emote, string CustomId);
 | 
			
		||||
public record NadekoInteractionData(IEmote Emote, string CustomId, string? Text = null);
 | 
			
		||||
@@ -3,11 +3,11 @@
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Interaction which only the author can use
 | 
			
		||||
/// </summary>
 | 
			
		||||
public abstract class NadekoOwnInteraction : NadekoInteraction
 | 
			
		||||
public abstract class NadekoButtonOwnInteraction : NadekoButtonInteraction
 | 
			
		||||
{
 | 
			
		||||
    protected readonly ulong _authorId;
 | 
			
		||||
 | 
			
		||||
    protected NadekoOwnInteraction(DiscordSocketClient client, ulong authorId) : base(client)
 | 
			
		||||
    protected NadekoButtonOwnInteraction(DiscordSocketClient client, ulong authorId) : base(client)
 | 
			
		||||
        => _authorId = authorId;
 | 
			
		||||
 | 
			
		||||
    protected override ValueTask<bool> Validate(SocketMessageComponent smc)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										26
									
								
								src/NadekoBot/Common/NInteraction.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/NadekoBot/Common/NInteraction.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
namespace NadekoBot.Common;
 | 
			
		||||
 | 
			
		||||
public abstract class NInteraction
 | 
			
		||||
{
 | 
			
		||||
    private readonly DiscordSocketClient _client;
 | 
			
		||||
    private readonly ulong _userId;
 | 
			
		||||
    private readonly Func<SocketMessageComponent, Task> _action;
 | 
			
		||||
 | 
			
		||||
    protected abstract NadekoInteractionData Data { get; }
 | 
			
		||||
 | 
			
		||||
    public NInteraction(
 | 
			
		||||
        DiscordSocketClient client,
 | 
			
		||||
        ulong userId,
 | 
			
		||||
        Func<SocketMessageComponent, Task> action)
 | 
			
		||||
    {
 | 
			
		||||
        _client = client;
 | 
			
		||||
        _userId = userId;
 | 
			
		||||
        _action = action;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public NadekoButtonInteraction GetInteraction()
 | 
			
		||||
        => new NadekoInteractionBuilder()
 | 
			
		||||
           .WithData(Data)
 | 
			
		||||
           .WithAction(_action)
 | 
			
		||||
           .Build(_client, _userId);
 | 
			
		||||
}
 | 
			
		||||
@@ -36,7 +36,7 @@ public abstract class NadekoModule : ModuleBase
 | 
			
		||||
        string error,
 | 
			
		||||
        string url = null,
 | 
			
		||||
        string footer = null, 
 | 
			
		||||
        NadekoInteraction inter = null)
 | 
			
		||||
        NadekoButtonInteraction inter = null)
 | 
			
		||||
        => ctx.Channel.SendErrorAsync(_eb, title, error, url, footer);
 | 
			
		||||
    
 | 
			
		||||
    public Task<IUserMessage> SendConfirmAsync(
 | 
			
		||||
@@ -47,32 +47,32 @@ public abstract class NadekoModule : ModuleBase
 | 
			
		||||
        => ctx.Channel.SendConfirmAsync(_eb, title, text, url, footer);
 | 
			
		||||
 | 
			
		||||
    // 
 | 
			
		||||
    public Task<IUserMessage> SendErrorAsync(string text, NadekoInteraction inter = null)
 | 
			
		||||
    public Task<IUserMessage> SendErrorAsync(string text, NadekoButtonInteraction inter = null)
 | 
			
		||||
        => ctx.Channel.SendAsync(_eb, text, MessageType.Error, inter);
 | 
			
		||||
    public Task<IUserMessage> SendConfirmAsync(string text, NadekoInteraction inter = null)
 | 
			
		||||
    public Task<IUserMessage> SendConfirmAsync(string text, NadekoButtonInteraction inter = null)
 | 
			
		||||
        => ctx.Channel.SendAsync(_eb, text, MessageType.Ok, inter);
 | 
			
		||||
    public Task<IUserMessage> SendPendingAsync(string text, NadekoInteraction inter = null)
 | 
			
		||||
    public Task<IUserMessage> SendPendingAsync(string text, NadekoButtonInteraction inter = null)
 | 
			
		||||
        => ctx.Channel.SendAsync(_eb, text, MessageType.Pending, inter);
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    // localized normal
 | 
			
		||||
    public Task<IUserMessage> ErrorLocalizedAsync(LocStr str, NadekoInteraction inter = null)
 | 
			
		||||
    public Task<IUserMessage> ErrorLocalizedAsync(LocStr str, NadekoButtonInteraction inter = null)
 | 
			
		||||
        => SendErrorAsync(GetText(str), inter);
 | 
			
		||||
 | 
			
		||||
    public Task<IUserMessage> PendingLocalizedAsync(LocStr str, NadekoInteraction inter = null)
 | 
			
		||||
    public Task<IUserMessage> PendingLocalizedAsync(LocStr str, NadekoButtonInteraction inter = null)
 | 
			
		||||
        => SendPendingAsync(GetText(str), inter);
 | 
			
		||||
 | 
			
		||||
    public Task<IUserMessage> ConfirmLocalizedAsync(LocStr str, NadekoInteraction inter = null)
 | 
			
		||||
    public Task<IUserMessage> ConfirmLocalizedAsync(LocStr str, NadekoButtonInteraction inter = null)
 | 
			
		||||
        => SendConfirmAsync(GetText(str), inter);
 | 
			
		||||
 | 
			
		||||
    // localized replies
 | 
			
		||||
    public Task<IUserMessage> ReplyErrorLocalizedAsync(LocStr str, NadekoInteraction inter = null)
 | 
			
		||||
    public Task<IUserMessage> ReplyErrorLocalizedAsync(LocStr str, NadekoButtonInteraction inter = null)
 | 
			
		||||
        => SendErrorAsync($"{Format.Bold(ctx.User.ToString())} {GetText(str)}");
 | 
			
		||||
 | 
			
		||||
    public Task<IUserMessage> ReplyPendingLocalizedAsync(LocStr str, NadekoInteraction inter = null)
 | 
			
		||||
    public Task<IUserMessage> ReplyPendingLocalizedAsync(LocStr str, NadekoButtonInteraction inter = null)
 | 
			
		||||
        => SendPendingAsync($"{Format.Bold(ctx.User.ToString())} {GetText(str)}");
 | 
			
		||||
 | 
			
		||||
    public Task<IUserMessage> ReplyConfirmLocalizedAsync(LocStr str, NadekoInteraction inter = null)
 | 
			
		||||
    public Task<IUserMessage> ReplyConfirmLocalizedAsync(LocStr str, NadekoButtonInteraction inter = null)
 | 
			
		||||
        => SendConfirmAsync($"{Format.Bold(ctx.User.ToString())} {GetText(str)}");
 | 
			
		||||
 | 
			
		||||
    public async Task<bool> PromptUserConfirmAsync(IEmbedBuilder embed)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,4 @@
 | 
			
		||||
#nullable disable
 | 
			
		||||
using Newtonsoft.Json;
 | 
			
		||||
using Newtonsoft.Json.Linq;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot;
 | 
			
		||||
@@ -45,7 +44,6 @@ public abstract record SmartText
 | 
			
		||||
            _ => throw new ArgumentOutOfRangeException(nameof(text))
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
    [CanBeNull]
 | 
			
		||||
    public static SmartText CreateFrom(string input)
 | 
			
		||||
    {
 | 
			
		||||
        if (string.IsNullOrWhiteSpace(input))
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user