mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-11 09:48:26 -04:00
5.1
This commit is contained in:
@@ -4,8 +4,9 @@ namespace NadekoBot;
|
||||
public interface IBotCredentials
|
||||
{
|
||||
string Token { get; }
|
||||
string GoogleApiKey { get; }
|
||||
string NadekoAiToken { get; }
|
||||
ICollection<ulong> OwnerIds { get; set; }
|
||||
string GoogleApiKey { get; }
|
||||
bool UsePrivilegedIntents { get; }
|
||||
string RapidApiKey { get; }
|
||||
|
||||
|
@@ -29,6 +29,15 @@ public sealed class Creds : IBotCredentials
|
||||
""")]
|
||||
public int TotalShards { get; set; }
|
||||
|
||||
[Comment("""
|
||||
Pledge 5$ or more on https://patreon.com/nadekobot and connect your discord account to Patreon.
|
||||
Go to https://dashy.nadeko.bot and login with your discord account
|
||||
Go to the Keys page and click "Generate New Key" and copy it here
|
||||
You and anyone else with the permission to run `.prompt` command will be able to use natural language to run bot's commands.
|
||||
For example '@Bot how's the weather in Paris' will return the current weather in Paris as if you were to run `.weather Paris` command
|
||||
""")]
|
||||
public string NadekoAiToken { get; set; }
|
||||
|
||||
[Comment(
|
||||
"""
|
||||
Login to https://console.cloud.google.com, create a new project, go to APIs & Services -> Library -> YouTube Data API and enable it.
|
||||
@@ -64,7 +73,7 @@ public sealed class Creds : IBotCredentials
|
||||
[Comment("""Official cleverbot api key.""")]
|
||||
public string CleverbotApiKey { get; set; }
|
||||
|
||||
[Comment(@"Official GPT-3 api key.")]
|
||||
[Comment(@"OpenAi api key.")]
|
||||
public string Gpt3ApiKey { get; set; }
|
||||
|
||||
[Comment("""
|
||||
|
@@ -18,4 +18,5 @@ public sealed class NadekoButtonInteractionHandler : NadekoInteractionBase
|
||||
|
||||
public override void AddTo(ComponentBuilder cb)
|
||||
=> cb.WithButton(Button);
|
||||
|
||||
}
|
@@ -85,6 +85,9 @@ public abstract class NadekoInteractionBase
|
||||
|
||||
public Task ExecuteOnActionAsync(SocketMessageComponent smc)
|
||||
=> _onAction(smc);
|
||||
|
||||
public void SetCompleted()
|
||||
=> _interactionCompletedSource.TrySetResult(true);
|
||||
}
|
||||
|
||||
public sealed class NadekoModalSubmitHandler
|
||||
|
@@ -11,4 +11,4 @@ public class CultureInfoConverter : JsonConverter<CultureInfo>
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, CultureInfo value, JsonSerializerOptions options)
|
||||
=> writer.WriteStringValue(value.Name);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,30 @@
|
||||
using System.Globalization;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
public class NumberToStringConverter : JsonConverter<object>
|
||||
{
|
||||
public override bool CanConvert(Type typeToConvert)
|
||||
=> typeof(string) == typeToConvert;
|
||||
|
||||
public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonTokenType.Number:
|
||||
return reader.TryGetInt64(out var l)
|
||||
? l.ToString()
|
||||
: reader.GetDouble().ToString(CultureInfo.InvariantCulture);
|
||||
case JsonTokenType.String:
|
||||
return reader.GetString() ?? string.Empty;
|
||||
default:
|
||||
{
|
||||
using var document = JsonDocument.ParseValue(ref reader);
|
||||
return document.RootElement.Clone().ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
|
||||
=> writer.WriteStringValue(value.ToString());
|
||||
}
|
@@ -1,5 +1,12 @@
|
||||
namespace NadekoBot.Modules.Patronage;
|
||||
|
||||
public enum LimitedFeatureName
|
||||
{
|
||||
ChatBot,
|
||||
ReactionRole,
|
||||
Prune,
|
||||
|
||||
}
|
||||
public readonly struct FeatureLimitKey
|
||||
{
|
||||
public string PrettyName { get; init; }
|
||||
|
@@ -1,8 +0,0 @@
|
||||
namespace NadekoBot.Modules.Patronage;
|
||||
|
||||
public readonly struct FeatureQuotaStats
|
||||
{
|
||||
public (uint Cur, uint Max) Hourly { get; init; }
|
||||
public (uint Cur, uint Max) Daily { get; init; }
|
||||
public (uint Cur, uint Max) Monthly { get; init; }
|
||||
}
|
@@ -31,26 +31,15 @@ public interface IPatronageService
|
||||
/// </summary>
|
||||
/// <param name="userId">UserId for which to get the patron data for.</param>
|
||||
/// <returns>A patron with the specifeid userId</returns>
|
||||
public Task<Patron> GetPatronAsync(ulong userId);
|
||||
public Task<Patron?> GetPatronAsync(ulong userId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the quota statistic for the user/patron specified by the userId
|
||||
/// </summary>
|
||||
/// <param name="userId">UserId of the user for which to get the quota statistic for</param>
|
||||
/// <returns>Quota stats for the specified user</returns>
|
||||
Task<UserQuotaStats> GetUserQuotaStatistic(ulong userId);
|
||||
|
||||
Task<bool> LimitHitAsync(LimitedFeatureName key, ulong userId, int amount = 1);
|
||||
Task<bool> LimitForceHit(LimitedFeatureName key, ulong userId, int amount);
|
||||
Task<QuotaLimit> GetUserLimit(LimitedFeatureName name, ulong userId);
|
||||
|
||||
Task<FeatureLimit> TryGetFeatureLimitAsync(FeatureLimitKey key, ulong userId, int? defaultValue);
|
||||
|
||||
ValueTask<OneOf<(uint Hourly, uint Daily, uint Monthly), QuotaLimit>> TryIncrementQuotaCounterAsync(
|
||||
ulong userId,
|
||||
bool isSelf,
|
||||
FeatureType featureType,
|
||||
string featureName,
|
||||
uint? maybeHourly,
|
||||
uint? maybeDaily,
|
||||
uint? maybeMonthly);
|
||||
Task<Dictionary<LimitedFeatureName, (int, QuotaLimit)>> LimitStats(ulong userId);
|
||||
|
||||
PatronConfigData GetConfig();
|
||||
int PercentBonus(Patron? user);
|
||||
int PercentBonus(long amount);
|
||||
}
|
@@ -13,7 +13,7 @@ public readonly struct Patron
|
||||
public ulong UserId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Amount the Patron is currently pledging or paid
|
||||
/// Amount the Patron is currently pledging or paid in cents
|
||||
/// </summary>
|
||||
public int Amount { get; init; }
|
||||
|
||||
|
@@ -7,31 +7,11 @@ namespace NadekoBot.Modules.Patronage;
|
||||
public partial class PatronConfigData : ICloneable<PatronConfigData>
|
||||
{
|
||||
[Comment("DO NOT CHANGE")]
|
||||
public int Version { get; set; } = 2;
|
||||
|
||||
public int Version { get; set; } = 3;
|
||||
|
||||
[Comment("Whether the patronage feature is enabled")]
|
||||
public bool IsEnabled { get; set; }
|
||||
|
||||
[Comment("List of patron only features and relevant quota data")]
|
||||
public FeatureQuotas Quotas { get; set; }
|
||||
|
||||
public PatronConfigData()
|
||||
{
|
||||
Quotas = new();
|
||||
}
|
||||
|
||||
public class FeatureQuotas
|
||||
{
|
||||
[Comment("Dictionary of feature names with their respective limits. Set to null for unlimited")]
|
||||
public Dictionary<string, Dictionary<PatronTier, int?>> Features { get; set; } = new();
|
||||
|
||||
[Comment("Dictionary of commands with their respective quota data")]
|
||||
public Dictionary<string, Dictionary<PatronTier, Dictionary<QuotaPer, uint>?>> Commands { get; set; } = new();
|
||||
|
||||
[Comment("Dictionary of groups with their respective quota data")]
|
||||
public Dictionary<string, Dictionary<PatronTier, Dictionary<QuotaPer, uint>?>> Groups { get; set; } = new();
|
||||
|
||||
[Comment("Dictionary of modules with their respective quota data")]
|
||||
public Dictionary<string, Dictionary<PatronTier, Dictionary<QuotaPer, uint>?>> Modules { get; set; } = new();
|
||||
}
|
||||
[Comment("Who can do how much of what")]
|
||||
public Dictionary<int, Dictionary<LimitedFeatureName, QuotaLimit>> Limits { get; set; } = new();
|
||||
}
|
@@ -8,15 +8,6 @@ public static class PatronExtensions
|
||||
_ => $"Patron Tier {tier}",
|
||||
};
|
||||
|
||||
public static string ToFullName(this QuotaPer per)
|
||||
=> per switch
|
||||
{
|
||||
QuotaPer.PerDay => "per day",
|
||||
QuotaPer.PerHour => "per hour",
|
||||
QuotaPer.PerMonth => "per month",
|
||||
_ => "Unknown",
|
||||
};
|
||||
|
||||
public static DateTime DayOfNextMonth(this DateTime date, int day)
|
||||
{
|
||||
var nextMonth = date.AddMonths(1);
|
||||
|
@@ -10,57 +10,16 @@ public readonly struct QuotaLimit
|
||||
/// <summary>
|
||||
/// Amount of usages reached, which is the limit
|
||||
/// </summary>
|
||||
public uint Quota { get; init; }
|
||||
public int Quota { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Which period is this quota limit for (hourly, daily, monthly, etc...)
|
||||
/// </summary>
|
||||
public QuotaPer QuotaPeriod { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// When does this quota limit reset
|
||||
/// </summary>
|
||||
public DateTime ResetsAt { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Type of the feature this quota limit is for
|
||||
/// </summary>
|
||||
public FeatureType FeatureType { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the feature this quota limit is for
|
||||
/// </summary>
|
||||
public string Feature { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether it is the user's own quota (true), or server owners (false)
|
||||
/// </summary>
|
||||
public bool IsOwnQuota { get; init; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Respresent information about the feature limit
|
||||
/// </summary>
|
||||
public readonly struct FeatureLimit
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Whether this limit comes from the patronage system
|
||||
/// </summary>
|
||||
public bool IsPatronLimit { get; init; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum limit allowed
|
||||
/// </summary>
|
||||
public int? Quota { get; init; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Name of the limit
|
||||
/// </summary>
|
||||
public string Name { get; init; } = string.Empty;
|
||||
|
||||
public FeatureLimit()
|
||||
public QuotaLimit(int quota, QuotaPer quotaPeriod)
|
||||
{
|
||||
Quota = quota;
|
||||
QuotaPeriod = quotaPeriod;
|
||||
}
|
||||
}
|
@@ -5,4 +5,5 @@ public enum QuotaPer
|
||||
PerHour,
|
||||
PerDay,
|
||||
PerMonth,
|
||||
Total,
|
||||
}
|
@@ -1,25 +0,0 @@
|
||||
namespace NadekoBot.Modules.Patronage;
|
||||
|
||||
public readonly struct UserQuotaStats
|
||||
{
|
||||
private static readonly IReadOnlyDictionary<string, FeatureQuotaStats> _emptyDictionary
|
||||
= new Dictionary<string, FeatureQuotaStats>();
|
||||
public PatronTier Tier { get; init; }
|
||||
= PatronTier.None;
|
||||
|
||||
public IReadOnlyDictionary<string, FeatureQuotaStats> Features { get; init; }
|
||||
= _emptyDictionary;
|
||||
|
||||
public IReadOnlyDictionary<string, FeatureQuotaStats> Commands { get; init; }
|
||||
= _emptyDictionary;
|
||||
|
||||
public IReadOnlyDictionary<string, FeatureQuotaStats> Groups { get; init; }
|
||||
= _emptyDictionary;
|
||||
|
||||
public IReadOnlyDictionary<string, FeatureQuotaStats> Modules { get; init; }
|
||||
= _emptyDictionary;
|
||||
|
||||
public UserQuotaStats()
|
||||
{
|
||||
}
|
||||
}
|
@@ -11,6 +11,10 @@ public partial class ResponseBuilder
|
||||
private readonly ResponseBuilder _builder;
|
||||
private readonly DiscordSocketClient _client;
|
||||
private int currentPage;
|
||||
|
||||
private NadekoButtonInteractionHandler left;
|
||||
private NadekoButtonInteractionHandler right;
|
||||
private NadekoInteractionBase? extra;
|
||||
|
||||
public PaginationSender(
|
||||
SourcedPaginatedResponseBuilder<T> paginationBuilder,
|
||||
@@ -106,6 +110,8 @@ public partial class ResponseBuilder
|
||||
|
||||
return (leftBtnInter, maybeInter, rightBtnInter);
|
||||
}
|
||||
|
||||
(left, extra, right) = await GetInteractions();
|
||||
|
||||
async Task UpdatePageAsync(SocketMessageComponent smc)
|
||||
{
|
||||
@@ -114,21 +120,25 @@ public partial class ResponseBuilder
|
||||
if (_paginationBuilder.AddPaginatedFooter)
|
||||
toSend.AddPaginatedFooter(currentPage, lastPage);
|
||||
|
||||
var (left, extra, right) = (await GetInteractions());
|
||||
left.SetCompleted();
|
||||
right.SetCompleted();
|
||||
extra?.SetCompleted();
|
||||
(left, extra, right) = (await GetInteractions());
|
||||
|
||||
var cb = new ComponentBuilder();
|
||||
left.AddTo(cb);
|
||||
right.AddTo(cb);
|
||||
extra?.AddTo(cb);
|
||||
|
||||
|
||||
await smc.ModifyOriginalResponseAsync(x =>
|
||||
{
|
||||
x.Embed = toSend.Build();
|
||||
x.Components = cb.Build();
|
||||
});
|
||||
|
||||
await Task.WhenAll(left.RunAsync(smc.Message), extra?.RunAsync(smc.Message) ?? Task.CompletedTask, right.RunAsync(smc.Message));
|
||||
}
|
||||
|
||||
var (left, extra, right) = await GetInteractions();
|
||||
|
||||
var cb = new ComponentBuilder();
|
||||
left.AddTo(cb);
|
||||
@@ -144,9 +154,11 @@ public partial class ResponseBuilder
|
||||
|
||||
if (lastPage == 0 && _paginationBuilder.InteractionFunc is null)
|
||||
return;
|
||||
|
||||
|
||||
await Task.WhenAll(left.RunAsync(msg), extra?.RunAsync(msg) ?? Task.CompletedTask, right.RunAsync(msg));
|
||||
|
||||
await Task.Delay(30_000);
|
||||
|
||||
await msg.ModifyAsync(mp => mp.Components = new ComponentBuilder().Build());
|
||||
}
|
||||
}
|
||||
|
@@ -9,7 +9,7 @@ namespace NadekoBot.Services;
|
||||
|
||||
public class CommandHandler : INService, IReadyExecutor, ICommandHandler
|
||||
{
|
||||
private const int GLOBAL_COMMANDS_COOLDOWN = 750;
|
||||
private const int GLOBAL_COMMANDS_COOLDOWN = 200;
|
||||
|
||||
private const float ONE_THOUSANDTH = 1.0f / 1000;
|
||||
|
||||
@@ -262,7 +262,7 @@ public class CommandHandler : INService, IReadyExecutor, ICommandHandler
|
||||
var blockTime = Environment.TickCount - startTime;
|
||||
|
||||
var messageContent = await _behaviorHandler.RunInputTransformersAsync(guild, usrMsg);
|
||||
|
||||
|
||||
var prefix = GetPrefix(guild?.Id);
|
||||
var isPrefixCommand = messageContent.StartsWith(".prefix", StringComparison.InvariantCultureIgnoreCase);
|
||||
// execute the command and measure the time it took
|
||||
|
@@ -27,4 +27,14 @@ public static class CommandContextExtensions
|
||||
|
||||
public static Task WarningAsync(this ICommandContext ctx)
|
||||
=> ctx.ReactAsync(MsgType.Pending);
|
||||
|
||||
|
||||
public static Task OkAsync(this IUserMessage msg)
|
||||
=> msg.AddReactionAsync(_okEmoji);
|
||||
|
||||
public static Task ErrorAsync(this IUserMessage msg)
|
||||
=> msg.AddReactionAsync(_errorEmoji);
|
||||
|
||||
public static Task WarningAsync(this IUserMessage msg)
|
||||
=> msg.AddReactionAsync(_warnEmoji);
|
||||
}
|
@@ -229,6 +229,7 @@ public static class Extensions
|
||||
public static IEnumerable<IRole> GetRoles(this IGuildUser user)
|
||||
=> user.RoleIds.Select(r => user.Guild.GetRole(r)).Where(r => r is not null);
|
||||
|
||||
// todo remove
|
||||
public static void Lap(this Stopwatch sw, string checkpoint)
|
||||
{
|
||||
Log.Information("Checkpoint {CheckPoint}: {Time}ms", checkpoint, sw.Elapsed.TotalMilliseconds);
|
||||
|
Reference in New Issue
Block a user