mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-11 01:38:27 -04:00
Fixed a nullref message when the bot is loading medusae. Added support for multiple embeds in features which support custom embeds in the form of
{plainText:text-here, embeds: [embedObject, embedObject, embedObject]}
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
using Cloneable;
|
#nullable enable
|
||||||
|
using Cloneable;
|
||||||
using NadekoBot.Common.Yml;
|
using NadekoBot.Common.Yml;
|
||||||
|
|
||||||
namespace Nadeko.Medusa;
|
namespace Nadeko.Medusa;
|
||||||
@@ -10,7 +11,7 @@ public sealed partial class MedusaConfig : ICloneable<MedusaConfig>
|
|||||||
public int Version { get; set; } = 1;
|
public int Version { get; set; } = 1;
|
||||||
|
|
||||||
[Comment("List of medusae automatically loaded at startup")]
|
[Comment("List of medusae automatically loaded at startup")]
|
||||||
public List<string> Loaded { get; set; }
|
public List<string>? Loaded { get; set; }
|
||||||
|
|
||||||
public MedusaConfig()
|
public MedusaConfig()
|
||||||
{
|
{
|
||||||
|
@@ -18,7 +18,7 @@ public sealed class MedusaConfigService : ConfigServiceBase<MedusaConfig>, IMedu
|
|||||||
}
|
}
|
||||||
|
|
||||||
public IReadOnlyCollection<string> GetLoadedMedusae()
|
public IReadOnlyCollection<string> GetLoadedMedusae()
|
||||||
=> Data.Loaded.ToList();
|
=> Data.Loaded?.ToList() ?? new List<string>();
|
||||||
|
|
||||||
public void AddLoadedMedusa(string name)
|
public void AddLoadedMedusa(string name)
|
||||||
{
|
{
|
||||||
@@ -26,6 +26,9 @@ public sealed class MedusaConfigService : ConfigServiceBase<MedusaConfig>, IMedu
|
|||||||
|
|
||||||
ModifyConfig(conf =>
|
ModifyConfig(conf =>
|
||||||
{
|
{
|
||||||
|
if (conf.Loaded is null)
|
||||||
|
conf.Loaded = new();
|
||||||
|
|
||||||
if(!conf.Loaded.Contains(name))
|
if(!conf.Loaded.Contains(name))
|
||||||
conf.Loaded.Add(name);
|
conf.Loaded.Add(name);
|
||||||
});
|
});
|
||||||
@@ -37,6 +40,9 @@ public sealed class MedusaConfigService : ConfigServiceBase<MedusaConfig>, IMedu
|
|||||||
|
|
||||||
ModifyConfig(conf =>
|
ModifyConfig(conf =>
|
||||||
{
|
{
|
||||||
|
if (conf.Loaded is null)
|
||||||
|
conf.Loaded = new();
|
||||||
|
|
||||||
conf.Loaded.Remove(name);
|
conf.Loaded.Remove(name);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -36,9 +36,17 @@ public class Replacer
|
|||||||
{
|
{
|
||||||
SmartEmbedText embedData => Replace(embedData),
|
SmartEmbedText embedData => Replace(embedData),
|
||||||
SmartPlainText plain => Replace(plain),
|
SmartPlainText plain => Replace(plain),
|
||||||
|
SmartEmbedTextArray arr => Replace(arr),
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(data), "Unsupported argument type")
|
_ => throw new ArgumentOutOfRangeException(nameof(data), "Unsupported argument type")
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public SmartEmbedTextArray Replace(SmartEmbedTextArray embedArr)
|
||||||
|
=> new()
|
||||||
|
{
|
||||||
|
Embeds = embedArr.Embeds.Map(Replace),
|
||||||
|
PlainText = Replace(embedArr.PlainText)
|
||||||
|
};
|
||||||
|
|
||||||
public SmartPlainText Replace(SmartPlainText plainText)
|
public SmartPlainText Replace(SmartPlainText plainText)
|
||||||
=> Replace(plainText.Text);
|
=> Replace(plainText.Text);
|
||||||
|
|
||||||
|
28
src/NadekoBot/Common/SmartText/SmartEmbedTextArray.cs
Normal file
28
src/NadekoBot/Common/SmartText/SmartEmbedTextArray.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#nullable disable
|
||||||
|
namespace NadekoBot;
|
||||||
|
|
||||||
|
public sealed record SmartEmbedTextArray : SmartText
|
||||||
|
{
|
||||||
|
public string PlainText { get; set; }
|
||||||
|
public SmartEmbedText[] Embeds { get; set; }
|
||||||
|
|
||||||
|
public bool IsValid
|
||||||
|
=> Embeds?.All(x => x.IsValid) ?? false;
|
||||||
|
|
||||||
|
public EmbedBuilder[] GetEmbedBuilders()
|
||||||
|
{
|
||||||
|
if (Embeds is null)
|
||||||
|
return Array.Empty<EmbedBuilder>();
|
||||||
|
|
||||||
|
return Embeds.Map(em => em.GetEmbed());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void NormalizeFields()
|
||||||
|
{
|
||||||
|
if (Embeds is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach(var eb in Embeds)
|
||||||
|
eb.NormalizeFields();
|
||||||
|
}
|
||||||
|
}
|
@@ -1,5 +1,5 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
using Newtonsoft.Json;
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace NadekoBot;
|
namespace NadekoBot;
|
||||||
|
|
||||||
@@ -11,6 +11,15 @@ public abstract record SmartText
|
|||||||
public bool IsPlainText
|
public bool IsPlainText
|
||||||
=> this is SmartPlainText;
|
=> this is SmartPlainText;
|
||||||
|
|
||||||
|
public bool IsEmbedArray
|
||||||
|
=> this is SmartEmbedTextArray;
|
||||||
|
|
||||||
|
private static readonly JsonSerializerOptions _opts = new JsonSerializerOptions()
|
||||||
|
{
|
||||||
|
PropertyNameCaseInsensitive = true,
|
||||||
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
||||||
|
};
|
||||||
|
|
||||||
public static SmartText operator +(SmartText text, string input)
|
public static SmartText operator +(SmartText text, string input)
|
||||||
=> text switch
|
=> text switch
|
||||||
{
|
{
|
||||||
@@ -19,6 +28,10 @@ public abstract record SmartText
|
|||||||
PlainText = set.PlainText + input
|
PlainText = set.PlainText + input
|
||||||
},
|
},
|
||||||
SmartPlainText spt => new SmartPlainText(spt.Text + input),
|
SmartPlainText spt => new SmartPlainText(spt.Text + input),
|
||||||
|
SmartEmbedTextArray arr => arr with
|
||||||
|
{
|
||||||
|
PlainText = arr.PlainText + input
|
||||||
|
},
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(text))
|
_ => throw new ArgumentOutOfRangeException(nameof(text))
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -30,27 +43,46 @@ public abstract record SmartText
|
|||||||
PlainText = input + set.PlainText
|
PlainText = input + set.PlainText
|
||||||
},
|
},
|
||||||
SmartPlainText spt => new SmartPlainText(input + spt.Text),
|
SmartPlainText spt => new SmartPlainText(input + spt.Text),
|
||||||
|
SmartEmbedTextArray arr => arr with
|
||||||
|
{
|
||||||
|
PlainText = input + arr.PlainText
|
||||||
|
},
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(text))
|
_ => throw new ArgumentOutOfRangeException(nameof(text))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
[CanBeNull]
|
||||||
public static SmartText CreateFrom(string input)
|
public static SmartText CreateFrom(string input)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(input) || !input.TrimStart().StartsWith("{"))
|
if (string.IsNullOrWhiteSpace(input))
|
||||||
return new SmartPlainText(input);
|
return new SmartPlainText(input);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var smartEmbedText = JsonConvert.DeserializeObject<SmartEmbedText>(input);
|
var doc = JsonDocument.Parse(input);
|
||||||
|
var root = doc.RootElement;
|
||||||
|
if (root.ValueKind == JsonValueKind.Object)
|
||||||
|
{
|
||||||
|
if (root.TryGetProperty("embeds", out _))
|
||||||
|
{
|
||||||
|
var arr = root.Deserialize<SmartEmbedTextArray>(_opts);
|
||||||
|
|
||||||
if (smartEmbedText is null)
|
if (arr is null)
|
||||||
throw new FormatException();
|
return new SmartPlainText(input);
|
||||||
|
|
||||||
smartEmbedText.NormalizeFields();
|
arr!.NormalizeFields();
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
if (!smartEmbedText.IsValid)
|
var obj = root.Deserialize<SmartEmbedText>(_opts);
|
||||||
return new SmartPlainText(input);
|
|
||||||
|
|
||||||
return smartEmbedText;
|
if (obj is null)
|
||||||
|
return new SmartPlainText(input);
|
||||||
|
|
||||||
|
obj.NormalizeFields();
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SmartPlainText(input);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
@@ -530,7 +530,7 @@ public class UserPunishService : INService, IReadyExecutor
|
|||||||
return default;
|
return default;
|
||||||
// if template is an embed, send that embed with replacements
|
// if template is an embed, send that embed with replacements
|
||||||
// otherwise, treat template as a regular string with replacements
|
// otherwise, treat template as a regular string with replacements
|
||||||
else if (!SmartText.CreateFrom(template).IsEmbed)
|
else if (SmartText.CreateFrom(template) is not { IsEmbed: true } or { IsEmbedArray: true })
|
||||||
{
|
{
|
||||||
template = JsonConvert.SerializeObject(new
|
template = JsonConvert.SerializeObject(new
|
||||||
{
|
{
|
||||||
|
@@ -81,8 +81,7 @@ public class HelpService : IExecNoCommand, INService
|
|||||||
em.AddField(GetText(strs.requires, guild), string.Join("\n", reqs));
|
em.AddField(GetText(strs.requires, guild), string.Join("\n", reqs));
|
||||||
|
|
||||||
em.AddField(_strings.GetText(strs.usage),
|
em.AddField(_strings.GetText(strs.usage),
|
||||||
string.Join("\n",
|
string.Join("\n", com.RealRemarksArr(_strings,_medusae, culture, prefix).Map(arg => Format.Code(arg))))
|
||||||
Array.ConvertAll(com.RealRemarksArr(_strings,_medusae, culture, prefix), arg => Format.Code(arg))))
|
|
||||||
.WithFooter(GetText(strs.module(com.Module.GetTopLevelModule().Name), guild))
|
.WithFooter(GetText(strs.module(com.Module.GetTopLevelModule().Name), guild))
|
||||||
.WithOkColor();
|
.WithOkColor();
|
||||||
|
|
||||||
|
@@ -46,7 +46,7 @@ public class RedisBotStringsProvider : IBotStringsProvider
|
|||||||
if (descStr == default)
|
if (descStr == default)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var args = Array.ConvertAll(argsStr.Split('&'), HttpUtility.UrlDecode);
|
var args = argsStr.Split('&').Map(HttpUtility.UrlDecode);
|
||||||
return new()
|
return new()
|
||||||
{
|
{
|
||||||
Args = args,
|
Args = args,
|
||||||
@@ -68,7 +68,7 @@ public class RedisBotStringsProvider : IBotStringsProvider
|
|||||||
{
|
{
|
||||||
var hashFields = localeStrings
|
var hashFields = localeStrings
|
||||||
.Select(x => new HashEntry($"{x.Key}::args",
|
.Select(x => new HashEntry($"{x.Key}::args",
|
||||||
string.Join('&', Array.ConvertAll(x.Value.Args, HttpUtility.UrlEncode))))
|
string.Join('&', x.Value.Args.Map(HttpUtility.UrlEncode))))
|
||||||
.Concat(localeStrings.Select(x => new HashEntry($"{x.Key}::desc", x.Value.Desc)))
|
.Concat(localeStrings.Select(x => new HashEntry($"{x.Key}::desc", x.Value.Desc)))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
|
@@ -23,6 +23,11 @@ public static class Extensions
|
|||||||
x.Embed = set.GetEmbed().Build();
|
x.Embed = set.GetEmbed().Build();
|
||||||
x.Content = set.PlainText?.SanitizeMentions() ?? "";
|
x.Content = set.PlainText?.SanitizeMentions() ?? "";
|
||||||
}),
|
}),
|
||||||
|
SmartEmbedTextArray set => msg.ModifyAsync(x =>
|
||||||
|
{
|
||||||
|
x.Embeds = set.GetEmbedBuilders().Map(eb => eb.Build());
|
||||||
|
x.Content = set.PlainText?.SanitizeMentions() ?? "";
|
||||||
|
}),
|
||||||
SmartPlainText spt => msg.ModifyAsync(x =>
|
SmartPlainText spt => msg.ModifyAsync(x =>
|
||||||
{
|
{
|
||||||
x.Content = spt.Text.SanitizeMentions();
|
x.Content = spt.Text.SanitizeMentions();
|
||||||
@@ -116,8 +121,7 @@ public static class Extensions
|
|||||||
args = strings.GetCommandStrings(cmd.Summary, culture).Args;
|
args = strings.GetCommandStrings(cmd.Summary, culture).Args;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Array.ConvertAll(args,
|
return args.Map(arg => GetFullUsage(cmd.Name, arg, prefix));
|
||||||
arg => GetFullUsage(cmd.Name, arg, prefix));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetFullUsage(string commandName, string args, string prefix)
|
private static string GetFullUsage(string commandName, string args, string prefix)
|
||||||
|
@@ -16,19 +16,22 @@ public static class MessageChannelExtensions
|
|||||||
public static Task<IUserMessage> SendAsync(
|
public static Task<IUserMessage> SendAsync(
|
||||||
this IMessageChannel channel,
|
this IMessageChannel channel,
|
||||||
string? plainText,
|
string? plainText,
|
||||||
Embed? embed,
|
Embed? embed = null,
|
||||||
|
Embed[]? embeds = null,
|
||||||
bool sanitizeAll = false)
|
bool sanitizeAll = false)
|
||||||
{
|
{
|
||||||
plainText = sanitizeAll ? plainText?.SanitizeAllMentions() ?? "" : plainText?.SanitizeMentions() ?? "";
|
plainText = sanitizeAll ? plainText?.SanitizeAllMentions() ?? "" : plainText?.SanitizeMentions() ?? "";
|
||||||
|
|
||||||
return channel.SendMessageAsync(plainText, embed: embed);
|
return channel.SendMessageAsync(plainText, embed: embed, embeds: embeds);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Task<IUserMessage> SendAsync(this IMessageChannel channel, SmartText text, bool sanitizeAll = false)
|
public static Task<IUserMessage> SendAsync(this IMessageChannel channel, SmartText text, bool sanitizeAll = false)
|
||||||
=> text switch
|
=> text switch
|
||||||
{
|
{
|
||||||
SmartEmbedText set => channel.SendAsync(set.PlainText, set.GetEmbed().Build(), sanitizeAll),
|
SmartEmbedText set => channel.SendAsync(set.PlainText, set.GetEmbed().Build(), sanitizeAll: sanitizeAll),
|
||||||
SmartPlainText st => channel.SendAsync(st.Text, null, sanitizeAll),
|
SmartPlainText st => channel.SendAsync(st.Text, null, sanitizeAll: sanitizeAll),
|
||||||
|
SmartEmbedTextArray arr => channel.SendAsync(arr.PlainText,
|
||||||
|
embeds: arr.GetEmbedBuilders().Map(e => e.Build())),
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(text))
|
_ => throw new ArgumentOutOfRangeException(nameof(text))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user