Part2 of the response system rework

This commit is contained in:
Kwoth
2024-04-29 01:13:45 +00:00
parent 4bab94b329
commit d28c7b500d
128 changed files with 2723 additions and 2289 deletions

View File

@@ -7,7 +7,7 @@ public abstract class CleanupModuleBase : NadekoModule
{
try
{
var embed = _eb.Create()
var embed = new EmbedBuilder()
.WithTitle(GetText(strs.sql_confirm_exec))
.WithDescription(name);
@@ -19,7 +19,7 @@ public abstract class CleanupModuleBase : NadekoModule
}
catch (Exception ex)
{
await SendErrorAsync(ex.ToString());
await Response().Error(ex.ToString()).SendAsync();
}
}
}

View File

@@ -37,8 +37,8 @@ public sealed class DmContextAdapter : DmContext
_localization = new(_services.GetRequiredService<ILocalization>());
}
public override IEmbedBuilder Embed()
=> _ebs.Value.Create();
public override EmbedBuilder Embed()
=> new EmbedBuilder();
public override string GetText(string key, object[]? args = null)
{

View File

@@ -18,7 +18,7 @@ public sealed class GuildContextAdapter : GuildContext
public override IGuildUser User { get; }
public override IEmbedBuilder Embed()
public override EmbedBuilder Embed()
=> _ebs.Value.Create();
public GuildContextAdapter(ICommandContext ctx, IMedusaStrings strings, IServiceProvider services)

View File

@@ -19,6 +19,7 @@ public abstract class NadekoModule : ModuleBase
public IEmbedBuilderService _eb { get; set; }
public INadekoInteractionService _inter { get; set; }
public IReplacementService repSvc { get; set; }
public IMessageSenderService _sender { get; set; }
protected string prefix
=> _cmdHandler.GetPrefix(ctx.Guild);
@@ -26,67 +27,23 @@ public abstract class NadekoModule : ModuleBase
protected ICommandContext ctx
=> Context;
public ResponseBuilder Response()
=> new ResponseBuilder(Strings, _eb)
.Context(ctx);
protected override void BeforeExecute(CommandInfo command)
=> Culture = _localization.GetCultureInfo(ctx.Guild?.Id);
protected string GetText(in LocStr data)
=> Strings.GetText(data, Culture);
public Task<IUserMessage> SendErrorAsync(
string title,
string error,
string url = null,
string footer = null,
NadekoInteraction inter = null)
=> ctx.Channel.SendErrorAsync(_eb, title, error, url, footer);
public Task<IUserMessage> SendConfirmAsync(
string title,
string text,
string url = null,
string footer = null)
=> ctx.Channel.SendConfirmAsync(_eb, title, text, url, footer);
// public Task<IUserMessage> SendAsync(SmartText text, NadekoInteraction inter = null, IUserMessage replyTo = null)
// => ctx.Channel.SendAsync(_eb, text, MsgType.Ok, inter, replyTo: replyTo);
// colored
public Task<IUserMessage> SendErrorAsync(string text, NadekoInteraction inter = null)
=> ctx.Channel.SendAsync(_eb, text, MsgType.Error, inter, replyTo: ctx.Message);
public Task<IUserMessage> SendConfirmAsync(string text, NadekoInteraction inter = null)
=> ctx.Channel.SendAsync(_eb, text, MsgType.Ok, inter, replyTo: ctx.Message);
public Task<IUserMessage> SendPendingAsync(string text, NadekoInteraction inter = null)
=> ctx.Channel.SendAsync(_eb, text, MsgType.Pending, inter, replyTo: ctx.Message);
// localized normal
public Task<IUserMessage> ErrorLocalizedAsync(LocStr str, NadekoInteraction inter = null)
=> SendErrorAsync(GetText(str), inter);
public Task<IUserMessage> PendingLocalizedAsync(LocStr str, NadekoInteraction inter = null)
=> SendPendingAsync(GetText(str), inter);
public Task<IUserMessage> ConfirmLocalizedAsync(LocStr str, NadekoInteraction inter = null)
=> SendConfirmAsync(GetText(str), inter);
// localized replies
public Task<IUserMessage> ReplyErrorLocalizedAsync(LocStr str, NadekoInteraction inter = null)
=> SendErrorAsync($"{Format.Bold(ctx.User.ToString())} {GetText(str)}", inter);
public Task<IUserMessage> ReplyPendingLocalizedAsync(LocStr str, NadekoInteraction inter = null)
=> SendPendingAsync($"{Format.Bold(ctx.User.ToString())} {GetText(str)}", inter);
public Task<IUserMessage> ReplyConfirmLocalizedAsync(LocStr str, NadekoInteraction inter = null)
=> SendConfirmAsync($"{Format.Bold(ctx.User.ToString())} {GetText(str)}", inter);
public async Task<bool> PromptUserConfirmAsync(IEmbedBuilder embed)
public async Task<bool> PromptUserConfirmAsync(EmbedBuilder embed)
{
embed.WithPendingColor()
.WithFooter("yes/no");
.WithFooter("yes/no");
var msg = await ctx.Channel.EmbedAsync(embed);
var msg = await Response().Embed(embed).SendAsync();
try
{
var input = await GetUserInputAsync(ctx.User.Id, ctx.Channel.Id);
@@ -140,9 +97,6 @@ public abstract class NadekoModule : ModuleBase
return Task.CompletedTask;
}
}
public Task<IUserMessage> EmbedAsync(IEmbedBuilder embed, string msg = "", IReadOnlyCollection<IEmbedBuilder> embeds = null)
=> ctx.Channel.EmbedAsync(embed, msg, replyTo: ctx.Message);
}
public abstract class NadekoModule<TService> : NadekoModule

View File

@@ -0,0 +1,7 @@
namespace NadekoBot.Extensions;
public interface IMessageSenderService
{
ResponseBuilder Response(IMessageChannel channel);
ResponseBuilder Response(ICommandContext hannel);
}

View File

@@ -1,7 +1,11 @@
namespace NadekoBot.Extensions;
namespace NadekoBot.Extensions;
public static class MessageChannelExtensions
{
public static ResponseBuilder Response(this IMessageChannel channel, IBotStrings bs, IEmbedBuilderService ebs)
=> new ResponseBuilder(bs, ebs)
.Channel(channel);
// main overload that all other send methods reduce to
public static Task<IUserMessage> SendAsync(
this IMessageChannel channel,
@@ -33,7 +37,7 @@ public static class MessageChannelExtensions
if (replyTo.Channel.Id != source.Id)
return null;
return new(replyTo.Id,
replyTo.Channel.Id,
(replyTo.Channel as ITextChannel)?.GuildId,
@@ -86,7 +90,7 @@ public static class MessageChannelExtensions
public static Task<IUserMessage> EmbedAsync(
this IMessageChannel ch,
IEmbedBuilder? embed,
EmbedBuilder? embed,
string plainText = "",
IReadOnlyCollection<IEmbedBuilder>? embeds = null,
NadekoInteraction? inter = null,
@@ -96,89 +100,13 @@ public static class MessageChannelExtensions
embed: embed?.Build(),
embeds: embeds?.Map(x => x.Build()),
replyTo: replyTo);
public static Task<IUserMessage> SendAsync(
this IMessageChannel ch,
IEmbedBuilderService eb,
string text,
MsgType type,
NadekoInteraction? inter = null,
IUserMessage? replyTo = null)
{
var builder = eb.Create().WithDescription(text);
builder = (type switch
{
MsgType.Error => builder.WithErrorColor(),
MsgType.Ok => builder.WithOkColor(),
MsgType.Pending => builder.WithPendingColor(),
_ => throw new ArgumentOutOfRangeException(nameof(type))
});
return ch.EmbedAsync(builder, inter: inter, replyTo: replyTo);
}
public static Task<IUserMessage> SendConfirmAsync(this IMessageChannel ch, IEmbedBuilderService eb, string text)
=> ch.SendAsync(eb, text, MsgType.Ok);
public static Task<IUserMessage> SendAsync(
this IMessageChannel ch,
IEmbedBuilderService eb,
MsgType type,
string? title,
string text,
string? url = null,
string? footer = null)
{
var embed = eb.Create()
.WithDescription(text)
.WithTitle(title);
if (url is not null && Uri.IsWellFormedUriString(url, UriKind.Absolute))
embed.WithUrl(url);
if (!string.IsNullOrWhiteSpace(footer))
embed.WithFooter(footer);
embed = type switch
{
MsgType.Error => embed.WithErrorColor(),
MsgType.Ok => embed.WithOkColor(),
MsgType.Pending => embed.WithPendingColor(),
_ => throw new ArgumentOutOfRangeException(nameof(type))
};
return ch.EmbedAsync(embed);
}
// embed title and optional footer overloads
public static Task<IUserMessage> SendConfirmAsync(
this IMessageChannel ch,
IEmbedBuilderService eb,
string? title,
string text,
string? url = null,
string? footer = null)
=> ch.SendAsync(eb, MsgType.Ok, title, text, url, footer);
public static Task<IUserMessage> SendErrorAsync(
this IMessageChannel ch,
IEmbedBuilderService eb,
string title,
string text,
string? url = null,
string? footer = null)
=> ch.SendAsync(eb, MsgType.Error, title, text, url, footer);
// regular send overloads
public static Task<IUserMessage> SendErrorAsync(this IMessageChannel ch, IEmbedBuilderService eb, string text)
=> ch.SendAsync(eb, text, MsgType.Error);
public static Task SendPaginatedConfirmAsync(
this ICommandContext ctx,
int currentPage,
Func<int, IEmbedBuilder> pageFunc,
Func<int, EmbedBuilder> pageFunc,
int totalElements,
int itemsPerPage,
bool addPaginatedFooter = true)
@@ -197,7 +125,7 @@ public static class MessageChannelExtensions
public static Task SendPaginatedConfirmAsync(
this ICommandContext ctx,
int currentPage,
Func<int, Task<IEmbedBuilder>> pageFunc,
Func<int, Task<EmbedBuilder>> pageFunc,
int totalElements,
int itemsPerPage,
bool addPaginatedFooter = true)
@@ -211,7 +139,7 @@ public static class MessageChannelExtensions
public static async Task SendPaginatedConfirmAsync<T>(
this ICommandContext ctx,
int currentPage,
Func<int, Task<IEmbedBuilder>> pageFunc,
Func<int, Task<EmbedBuilder>> pageFunc,
Func<int, ValueTask<SimpleInteraction<T>?>>? interFactory,
int totalElements,
int itemsPerPage,

View File

@@ -0,0 +1,24 @@
using System.Diagnostics.CodeAnalysis;
namespace NadekoBot.Extensions;
public sealed class MessageSenderService : IMessageSenderService, INService
{
private readonly IBotStrings _bs;
private readonly IEmbedBuilderService _ebs;
public MessageSenderService(IBotStrings bs, IEmbedBuilderService ebs)
{
_bs = bs;
_ebs = ebs;
}
public ResponseBuilder Response(IMessageChannel channel)
=> new ResponseBuilder(_bs, _ebs)
.Channel(channel);
public ResponseBuilder Response(ICommandContext ctx)
=> new ResponseBuilder(_bs, _ebs)
.Context(ctx);
}

View File

@@ -0,0 +1,252 @@
namespace NadekoBot.Extensions;
public sealed class ResponseBuilder
{
private ICommandContext? ctx = null;
private IMessageChannel? channel = null;
private Embed? embed = null;
private string? plainText = null;
private IReadOnlyCollection<EmbedBuilder>? embeds = null;
private IUserMessage? msg = null;
private IUser? user = null;
private bool sanitizeMentions = true;
private LocStr? locTxt;
private object[] locParams = [];
private bool shouldReply = true;
private readonly IBotStrings _bs;
private readonly IEmbedBuilderService _ebs;
private EmbedBuilder? embedBuilder = null;
public ResponseBuilder(IBotStrings bs, IEmbedBuilderService ebs)
{
_bs = bs;
_ebs = ebs;
}
private MessageReference? CreateMessageReference(IMessageChannel targetChannel)
{
if (!shouldReply)
return null;
var replyTo = msg ?? ctx?.Message;
// what message are we replying to
if (replyTo is null)
return null;
// we have to have a channel where we are sending the message in order to know whether we can reply to it
if (targetChannel.Id != replyTo.Channel.Id)
return null;
return new(replyTo.Id,
replyTo.Channel.Id,
(replyTo.Channel as ITextChannel)?.GuildId,
failIfNotExists: false);
}
public async Task<IUserMessage> SendAsync()
{
var targetChannel = InternalResolveChannel() ?? throw new ArgumentNullException(nameof(channel));
var msgReference = CreateMessageReference(targetChannel);
var txt = GetText(locTxt);
if (sanitizeMentions)
txt = txt?.SanitizeMentions(true);
return await targetChannel.SendMessageAsync(
txt,
embed: embed ?? embedBuilder?.Build(),
embeds: embeds?.Map(x => x.Build()),
components: null,
allowedMentions: sanitizeMentions ? new(AllowedMentionTypes.Users) : AllowedMentions.All,
messageReference: msgReference);
}
private ulong? InternalResolveGuildId(IMessageChannel? targetChannel)
=> ctx?.Guild?.Id ?? (targetChannel as ITextChannel)?.GuildId;
private IMessageChannel? InternalResolveChannel()
=> channel ?? ctx?.Channel ?? msg?.Channel;
private string? GetText(LocStr? locStr)
{
var targetChannel = InternalResolveChannel();
var guildId = InternalResolveGuildId(targetChannel);
return locStr is LocStr ls ? _bs.GetText(ls.Key, guildId, locParams) : plainText;
}
private string GetText(LocStr locStr)
{
var targetChannel = InternalResolveChannel();
var guildId = InternalResolveGuildId(targetChannel);
return _bs.GetText(locStr.Key, guildId, locStr.Params);
}
public ResponseBuilder Text(LocStr str)
{
locTxt = str;
return this;
}
public ResponseBuilder Text(SmartText text)
{
if (text is SmartPlainText spt)
plainText = spt.Text;
else if (text is SmartEmbedText set)
embed = set.GetEmbed().Build();
else if (text is SmartEmbedTextArray ser)
embeds = ser.GetEmbedBuilders();
return this;
}
private ResponseBuilder InternalColoredText(string text, EmbedColor color)
{
embed = new EmbedBuilder()
.WithColor(color)
.WithDescription(text)
.Build();
return this;
}
private EmbedBuilder CreateEmbedInternal(
string? title,
string? text,
string? url,
string? footer = null)
{
var embed = new EmbedBuilder()
.WithTitle(title)
.WithDescription(text);
if (!string.IsNullOrWhiteSpace(url))
embed = embed.WithUrl(url);
if (!string.IsNullOrWhiteSpace(footer))
embed = embed.WithFooter(footer);
return embed;
}
private EmbedBuilder PaintEmbedInternal(EmbedBuilder eb, EmbedColor color)
=> color switch
{
EmbedColor.Ok => eb.WithOkColor(),
EmbedColor.Pending => eb.WithPendingColor(),
EmbedColor.Error => eb.WithErrorColor(),
};
public ResponseBuilder Error(
string? title,
string? text,
string? url = null,
string? footer = null)
{
var eb = CreateEmbedInternal(title, text, url, footer);
embed = PaintEmbedInternal(eb, EmbedColor.Error).Build();
return this;
}
public ResponseBuilder Confirm(
string? title,
string? text,
string? url = null,
string? footer = null)
{
var eb = CreateEmbedInternal(title, text, url, footer);
embed = PaintEmbedInternal(eb, EmbedColor.Error).Build();
return this;
}
public ResponseBuilder Confirm(string text)
=> InternalColoredText(text, EmbedColor.Ok);
public ResponseBuilder Confirm(LocStr str)
=> Confirm(GetText(str));
public ResponseBuilder Pending(string text)
=> InternalColoredText(text, EmbedColor.Ok);
public ResponseBuilder Pending(LocStr str)
=> Pending(GetText(str));
public ResponseBuilder Error(string text)
=> InternalColoredText(text, EmbedColor.Error);
public ResponseBuilder Error(LocStr str)
=> Error(GetText(str));
public ResponseBuilder UserBasedMentions()
{
sanitizeMentions = !((InternalResolveUser() as IGuildUser)?.GuildPermissions.MentionEveryone ?? false);
return this;
}
private IUser? InternalResolveUser()
=> ctx?.User ?? user ?? msg?.Author;
public ResponseBuilder Embed(EmbedBuilder eb)
{
embedBuilder = eb;
return this;
}
public ResponseBuilder Embed(Func<IEmbedBuilderService, EmbedBuilder> embedFactory)
{
// todo colors
this.embed = embedFactory(_ebs).Build();
return this;
}
public ResponseBuilder Channel(IMessageChannel channel)
{
this.channel = channel;
return this;
}
public ResponseBuilder Sanitize(bool shouldSantize = true)
{
sanitizeMentions = shouldSantize;
return this;
}
public ResponseBuilder Context(ICommandContext ctx)
{
this.ctx = ctx;
return this;
}
public ResponseBuilder Message(IUserMessage msg)
{
this.msg = msg;
return this;
}
public ResponseBuilder User(IUser user)
{
this.user = user;
return this;
}
public ResponseBuilder NoReply()
{
shouldReply = false;
return this;
}
public ResponseBuilder Interaction(NadekoInteraction inter)
{
// todo implement
return this;
}
public ResponseBuilder Embeds(IReadOnlyCollection<EmbedBuilder> inputEmbeds)
{
embeds = inputEmbeds;
return this;
}
}

View File

@@ -0,0 +1,18 @@
namespace NadekoBot.Extensions;
public static class ResponseBuilderExtensions
{
// todo delete this
public static EmbedBuilder WithColor(this EmbedBuilder eb, EmbedColor color)
=> eb;
public static EmbedBuilder WithPendingColor(this EmbedBuilder eb)
=> eb.WithColor(EmbedColor.Error);
public static EmbedBuilder WithOkColor(this EmbedBuilder eb)
=> eb.WithColor(EmbedColor.Ok);
public static EmbedBuilder WithErrorColor(this EmbedBuilder eb)
=> eb.WithColor(EmbedColor.Error);
}

View File

@@ -1,12 +1,12 @@
#nullable disable
using NadekoBot.Common.Configs;
// todo remove
namespace NadekoBot.Services;
public interface IEmbedBuilderService
{
IEmbedBuilder Create(ICommandContext ctx = null);
IEmbedBuilder Create(EmbedBuilder eb);
EmbedBuilder Create(ICommandContext ctx = null);
}
public class EmbedBuilderService : IEmbedBuilderService, INService
@@ -16,11 +16,9 @@ public class EmbedBuilderService : IEmbedBuilderService, INService
public EmbedBuilderService(BotConfigService botConfigService)
=> _botConfigService = botConfigService;
public IEmbedBuilder Create(ICommandContext ctx = null)
=> new DiscordEmbedBuilderWrapper(_botConfigService.Data);
public EmbedBuilder Create(ICommandContext ctx = null)
=> new EmbedBuilder();
public IEmbedBuilder Create(EmbedBuilder embed)
=> new DiscordEmbedBuilderWrapper(_botConfigService.Data, embed);
}
public sealed class DiscordEmbedBuilderWrapper : IEmbedBuilder
@@ -34,31 +32,31 @@ public sealed class DiscordEmbedBuilderWrapper : IEmbedBuilder
this.embed = embed ?? new EmbedBuilder();
}
public IEmbedBuilder WithDescription(string desc)
public EmbedBuilder WithDescription(string desc)
=> Wrap(embed.WithDescription(desc));
public IEmbedBuilder WithTitle(string title)
public EmbedBuilder WithTitle(string title)
=> Wrap(embed.WithTitle(title));
public IEmbedBuilder AddField(string title, object value, bool isInline = false)
public EmbedBuilder AddField(string title, object value, bool isInline = false)
=> Wrap(embed.AddField(title, value, isInline));
public IEmbedBuilder WithFooter(string text, string iconUrl = null)
public EmbedBuilder WithFooter(string text, string iconUrl = null)
=> Wrap(embed.WithFooter(text, iconUrl));
public IEmbedBuilder WithAuthor(string name, string iconUrl = null, string url = null)
public EmbedBuilder WithAuthor(string name, string iconUrl = null, string url = null)
=> Wrap(embed.WithAuthor(name, iconUrl, url));
public IEmbedBuilder WithUrl(string url)
public EmbedBuilder WithUrl(string url)
=> Wrap(embed.WithUrl(url));
public IEmbedBuilder WithImageUrl(string url)
public EmbedBuilder WithImageUrl(string url)
=> Wrap(embed.WithImageUrl(url));
public IEmbedBuilder WithThumbnailUrl(string url)
public EmbedBuilder WithThumbnailUrl(string url)
=> Wrap(embed.WithThumbnailUrl(url));
public IEmbedBuilder WithColor(EmbedColor color)
public EmbedBuilder WithColor(EmbedColor color)
=> color switch
{
EmbedColor.Ok => Wrap(embed.WithColor(_botConfig.Color.Ok.ToDiscordColor())),
@@ -67,15 +65,15 @@ public sealed class DiscordEmbedBuilderWrapper : IEmbedBuilder
_ => throw new ArgumentOutOfRangeException(nameof(color), "Unsupported EmbedColor type")
};
public IEmbedBuilder WithDiscordColor(Color color)
public EmbedBuilder WithDiscordColor(Color color)
=> Wrap(embed.WithColor(color));
public Embed Build()
=> embed.Build();
private IEmbedBuilder Wrap(EmbedBuilder eb)
private EmbedBuilder Wrap(EmbedBuilder eb)
{
embed = eb;
return this;
return eb;
}
}

View File

@@ -28,7 +28,7 @@ public sealed class CommandsUtilityService : ICommandsUtilityService, INService
_medusae = medusae;
}
public IEmbedBuilder GetCommandHelp(CommandInfo com, IGuild guild)
public EmbedBuilder GetCommandHelp(CommandInfo com, IGuild guild)
{
var prefix = _ch.GetPrefix(guild);
@@ -39,17 +39,19 @@ public sealed class CommandsUtilityService : ICommandsUtilityService, INService
var culture = _loc.GetCultureInfo(guild);
var em = _eb.Create()
.AddField(str, $"{com.RealSummary(_strings, _medusae, culture, prefix)}", true);
var em = new EmbedBuilder()
.AddField(str, $"{com.RealSummary(_strings, _medusae, culture, prefix)}", true);
_dpos.TryGetOverrides(guild?.Id ?? 0, com.Name, out var overrides);
var reqs = GetCommandRequirements(com, (GuildPermission?)overrides);
if (reqs.Any())
em.AddField(GetText(strs.requires, guild), string.Join("\n", reqs));
Extensions.Extensions.WithOkColor(em.AddField(_strings.GetText(strs.usage),
string.Join("\n", com.RealRemarksArr(_strings, _medusae, culture, prefix).Map(arg => Format.Code(arg))))
.WithFooter(GetText(strs.module(com.Module.GetTopLevelModule().Name), guild)));
em
.WithOkColor()
.AddField(_strings.GetText(strs.usage),
string.Join("\n", com.RealRemarksArr(_strings, _medusae, culture, prefix).Map(arg => Format.Code(arg))))
.WithFooter(GetText(strs.module(com.Module.GetTopLevelModule().Name), guild));
var opt = GetNadekoOptionType(com.Attributes);
if (opt is not null)
@@ -72,31 +74,31 @@ public sealed class CommandsUtilityService : ICommandsUtilityService, INService
public static List<string> GetCommandOptionHelpList(Type opt)
{
var strs = opt.GetProperties()
.Select(x => x.GetCustomAttributes(true).FirstOrDefault(a => a is OptionAttribute))
.Where(x => x is not null)
.Cast<OptionAttribute>()
.Select(x =>
{
var toReturn = $"`--{x.LongName}`";
.Select(x => x.GetCustomAttributes(true).FirstOrDefault(a => a is OptionAttribute))
.Where(x => x is not null)
.Cast<OptionAttribute>()
.Select(x =>
{
var toReturn = $"`--{x.LongName}`";
if (!string.IsNullOrWhiteSpace(x.ShortName))
toReturn += $" (`-{x.ShortName}`)";
if (!string.IsNullOrWhiteSpace(x.ShortName))
toReturn += $" (`-{x.ShortName}`)";
toReturn += $" {x.HelpText} ";
return toReturn;
})
.ToList();
toReturn += $" {x.HelpText} ";
return toReturn;
})
.ToList();
return strs;
}
public static Type? GetNadekoOptionType(IEnumerable<Attribute> attributes)
=> attributes
.Select(a => a.GetType())
.Where(a => a.IsGenericType
&& a.GetGenericTypeDefinition() == typeof(NadekoOptionsAttribute<>))
.Select(a => a.GenericTypeArguments[0])
.FirstOrDefault();
.Select(a => a.GetType())
.Where(a => a.IsGenericType
&& a.GetGenericTypeDefinition() == typeof(NadekoOptionsAttribute<>))
.Select(a => a.GenericTypeArguments[0])
.FirstOrDefault();
public static string[] GetCommandRequirements(CommandInfo cmd, GuildPerm? overrides = null)
{
@@ -107,38 +109,38 @@ public sealed class CommandsUtilityService : ICommandsUtilityService, INService
if (cmd.Preconditions.Any(x => x is NoPublicBotAttribute)
|| cmd.Module
.Preconditions
.Any(x => x is NoPublicBotAttribute)
.Preconditions
.Any(x => x is NoPublicBotAttribute)
|| cmd.Module.GetTopLevelModule()
.Preconditions
.Any(x => x is NoPublicBotAttribute))
.Preconditions
.Any(x => x is NoPublicBotAttribute))
toReturn.Add("No Public Bot");
if (cmd.Preconditions
.Any(x => x is OnlyPublicBotAttribute)
.Any(x => x is OnlyPublicBotAttribute)
|| cmd.Module
.Preconditions
.Any(x => x is OnlyPublicBotAttribute)
.Preconditions
.Any(x => x is OnlyPublicBotAttribute)
|| cmd.Module.GetTopLevelModule()
.Preconditions
.Any(x => x is OnlyPublicBotAttribute))
.Preconditions
.Any(x => x is OnlyPublicBotAttribute))
toReturn.Add("Only Public Bot");
var userPermString = cmd.Preconditions
.Where(ca => ca is UserPermAttribute)
.Cast<UserPermAttribute>()
.Select(userPerm =>
{
if (userPerm.ChannelPermission is { } cPerm)
return GetPreconditionString(cPerm);
.Where(ca => ca is UserPermAttribute)
.Cast<UserPermAttribute>()
.Select(userPerm =>
{
if (userPerm.ChannelPermission is { } cPerm)
return GetPreconditionString(cPerm);
if (userPerm.GuildPermission is { } gPerm)
return GetPreconditionString(gPerm);
if (userPerm.GuildPermission is { } gPerm)
return GetPreconditionString(gPerm);
return string.Empty;
})
.Where(x => !string.IsNullOrWhiteSpace(x))
.Join('\n');
return string.Empty;
})
.Where(x => !string.IsNullOrWhiteSpace(x))
.Join('\n');
if (overrides is null)
{
@@ -166,7 +168,7 @@ public sealed class CommandsUtilityService : ICommandsUtilityService, INService
=> _strings.GetText(str, guild?.Id);
}
public interface ICommandsUtilityService
public interface ICommandsUtilityService
{
IEmbedBuilder GetCommandHelp(CommandInfo com, IGuild guild);
EmbedBuilder GetCommandHelp(CommandInfo com, IGuild guild);
}

View File

@@ -17,6 +17,9 @@ public abstract record SmartText
[JsonIgnore]
public bool IsEmbedArray
=> this is SmartEmbedTextArray;
public static implicit operator SmartText(string input)
=> new SmartPlainText(input);
public static SmartText operator +(SmartText text, string input)
=> text switch

View File

@@ -18,8 +18,8 @@ public static class Extensions
private static readonly Regex _urlRegex =
new(@"^(https?|ftp)://(?<path>[^\s/$.?#].[^\s]*)$", RegexOptions.Compiled);
public static IEmbedBuilder WithAuthor(this IEmbedBuilder eb, IUser author)
=> eb.WithAuthor(author.ToString()!, author.RealAvatarUrl().ToString());
// public static EmbedBuilder WithAuthor(this EmbedBuilder eb, IUser author)
// => eb.WithAuthor(author.ToString()!, author.RealAvatarUrl().ToString());
public static Task EditAsync(this IUserMessage msg, SmartText text)
=> text switch
@@ -134,22 +134,22 @@ public static class Extensions
private static string GetFullUsage(string commandName, string args, string prefix)
=> $"{prefix}{commandName} {string.Format(args, prefix)}".TrimEnd();
public static IEmbedBuilder AddPaginatedFooter(this IEmbedBuilder embed, int curPage, int? lastPage)
public static EmbedBuilder AddPaginatedFooter(this EmbedBuilder embed, int curPage, int? lastPage)
{
if (lastPage is not null)
return embed.WithFooter($"{curPage + 1} / {lastPage + 1}");
return embed.WithFooter(curPage.ToString());
}
public static IEmbedBuilder WithOkColor(this IEmbedBuilder eb)
=> eb.WithColor(EmbedColor.Ok);
public static IEmbedBuilder WithPendingColor(this IEmbedBuilder eb)
=> eb.WithColor(EmbedColor.Pending);
public static IEmbedBuilder WithErrorColor(this IEmbedBuilder eb)
=> eb.WithColor(EmbedColor.Error);
// public static EmbedBuilder WithOkColor(this EmbedBuilder eb)
// => eb.WithColor(EmbedColor.Ok);
//
// public static EmbedBuilder WithPendingColor(this EmbedBuilder eb)
// => eb.WithColor(EmbedColor.Pending);
//
// public static EmbedBuilder WithErrorColor(this EmbedBuilder eb)
// => eb.WithColor(EmbedColor.Error);
//
public static IMessage DeleteAfter(this IUserMessage msg, float seconds, ILogCommandService? logService = null)
{
Task.Run(async () =>

View File

@@ -48,9 +48,9 @@ public static class SocketMessageComponentExtensions
public static Task EmbedAsync(
this SocketMessageComponent smc,
IEmbedBuilder? embed,
EmbedBuilder? embed,
string plainText = "",
IReadOnlyCollection<IEmbedBuilder>? embeds = null,
IReadOnlyCollection<EmbedBuilder>? embeds = null,
NadekoInteraction? inter = null,
bool ephemeral = false)
=> smc.RespondAsync(plainText,
@@ -66,7 +66,7 @@ public static class SocketMessageComponentExtensions
bool ephemeral = false,
NadekoInteraction? inter = null)
{
var builder = eb.Create().WithDescription(text);
var builder = new EmbedBuilder().WithDescription(text);
builder = (type switch
{
@@ -81,13 +81,6 @@ public static class SocketMessageComponentExtensions
// embed title and optional footer overloads
public static Task RespondErrorAsync(
this SocketMessageComponent smc,
IEmbedBuilderService eb,
string text,
bool ephemeral = false)
=> smc.RespondAsync(eb, text, MsgType.Error, ephemeral);
public static Task RespondConfirmAsync(
this SocketMessageComponent smc,
IEmbedBuilderService eb,

View File

@@ -4,7 +4,7 @@ namespace NadekoBot.Extensions;
public static class UserExtensions
{
public static async Task<IUserMessage> EmbedAsync(this IUser user, IEmbedBuilder embed, string msg = "")
public static async Task<IUserMessage> EmbedAsync(this IUser user, EmbedBuilder embed, string msg = "")
{
var ch = await user.CreateDMChannelAsync();
return await ch.EmbedAsync(embed, msg);
@@ -17,13 +17,7 @@ public static class UserExtensions
}
public static async Task<IUserMessage> SendConfirmAsync(this IUser user, IEmbedBuilderService eb, string text)
=> await user.SendMessageAsync("", embed: eb.Create().WithOkColor().WithDescription(text).Build());
public static async Task<IUserMessage> SendErrorAsync(this IUser user, IEmbedBuilderService eb, string error)
=> await user.SendMessageAsync("", embed: eb.Create().WithErrorColor().WithDescription(error).Build());
public static async Task<IUserMessage> SendPendingAsync(this IUser user, IEmbedBuilderService eb, string message)
=> await user.SendMessageAsync("", embed: eb.Create().WithPendingColor().WithDescription(message).Build());
=> await user.SendMessageAsync("", embed: new EmbedBuilder().WithOkColor().WithDescription(text).Build());
// This method is used by everything that fetches the avatar from a user
public static Uri RealAvatarUrl(this IUser usr, ushort size = 256)