Added .qimport and .qexport commands, fixed some response strings

This commit is contained in:
Kwoth
2021-12-11 15:27:32 +01:00
parent 02eb6e172b
commit 36c013fbb5
7 changed files with 164 additions and 5 deletions

View File

@@ -7,6 +7,7 @@ Experimental changelog. Mostly based on [keepachangelog](https://keepachangelog.
### Added
- `.remindl` and `.remindrm` commands now supports optional 'server' parameter for Administrators which allows them to delete any reminder created on the server
- Added slots.currencyFontColor to gambling.yml
- Added `.qexport` and `.qimport` commands which allow you to export and import quotes just like `.crsexport`
### Fixed
- `.crypto` now supports top 5000 coins

View File

@@ -9,6 +9,11 @@ namespace NadekoBot.Db
{
public static class QuoteExtensions
{
public static IEnumerable<Quote> GetForGuild(this DbSet<Quote> quotes, ulong guildId)
{
return quotes.AsQueryable().Where(x => x.GuildId == guildId);
}
public static IEnumerable<Quote> GetGroup(this DbSet<Quote> quotes, ulong guildId, int page, OrderType order)
{
var q = quotes.AsQueryable().Where(x => x.GuildId == guildId);

View File

@@ -310,7 +310,7 @@ namespace NadekoBot.Modules.CustomReactions
_ = ctx.Channel.TriggerTypingAsync();
var serialized = _service.ExportCrs(ctx.Guild?.Id);
using var stream = await serialized.ToStream();
await using var stream = await serialized.ToStream();
await ctx.Channel.SendFileAsync(stream, "crs-export.yml", text: null);
}

View File

@@ -7,10 +7,13 @@ using NadekoBot.Db.Models;
using NadekoBot.Extensions;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using NadekoBot.Common.Yml;
using NadekoBot.Services;
using NadekoBot.Services.Database.Models;
using NadekoBot.Db;
using YamlDotNet.Serialization;
namespace NadekoBot.Modules.Utility
{
@@ -20,10 +23,12 @@ namespace NadekoBot.Modules.Utility
public class QuoteCommands : NadekoSubmodule
{
private readonly DbService _db;
private readonly IHttpClientFactory _http;
public QuoteCommands(DbService db)
public QuoteCommands(DbService db, IHttpClientFactory http)
{
_db = db;
_http = http;
}
[NadekoCommand, Aliases]
@@ -248,6 +253,140 @@ namespace NadekoBot.Modules.Utility
await ReplyConfirmLocalizedAsync(strs.quotes_deleted(Format.Bold(keyword.SanitizeAllMentions()))).ConfigureAwait(false);
}
public class ExportedQuote
{
public static ExportedQuote FromModel(Quote quote)
=> new ExportedQuote()
{
Id = ((kwum)quote.Id).ToString(),
An = quote.AuthorName,
Aid = quote.AuthorId,
Txt = quote.Text
};
public string Id { get; set; }
public string An { get; set; }
public ulong Aid { get; set; }
public string Txt { get; set; }
}
private const string _prependExport =
@"# Keys are keywords, Each key has a LIST of quotes in the following format:
# - id: Alphanumeric id used for commands related to the quote. (Note, when using .quotesimport, a new id will be generated.)
# an: Author name
# aid: Author id
# txt: Quote text
";
private static readonly ISerializer _exportSerializer = new SerializerBuilder()
.WithEventEmitter(args => new MultilineScalarFlowStyleEmitter(args))
.WithNamingConvention(YamlDotNet.Serialization.NamingConventions.CamelCaseNamingConvention.Instance)
.WithIndentedSequences()
.ConfigureDefaultValuesHandling(DefaultValuesHandling.OmitDefaults)
.DisableAliases()
.Build();
[NadekoCommand, Aliases]
[RequireContext(ContextType.Guild)]
[RequireUserPermission(GuildPermission.Administrator)]
public async Task QuotesExport()
{
IEnumerable<Quote> quotes;
using (var uow = _db.GetDbContext())
{
quotes = uow.Quotes
.GetForGuild(ctx.Guild.Id)
.ToList();
}
var crsDict = quotes
.GroupBy(x => x.Keyword)
.ToDictionary(x => x.Key, x => x.Select(ExportedQuote.FromModel));
var text = _prependExport + _exportSerializer
.Serialize(crsDict)
.UnescapeUnicodeCodePoints();
await using var stream = await text.ToStream();
await ctx.Channel.SendFileAsync(stream, "quote-export.yml", text: null);
}
[NadekoCommand, Aliases]
[RequireContext(ContextType.Guild)]
[RequireUserPermission(GuildPermission.Administrator)]
[Ratelimit(300)]
#if GLOBAL_NADEKO
[OwnerOnly]
#endif
public async Task QuotesImport([Leftover]string input = null)
{
input = input?.Trim();
_ = ctx.Channel.TriggerTypingAsync();
if (input is null)
{
var attachment = ctx.Message.Attachments.FirstOrDefault();
if (attachment is null)
{
await ReplyErrorLocalizedAsync(strs.expr_import_no_input);
return;
}
using var client = _http.CreateClient();
input = await client.GetStringAsync(attachment.Url);
if (string.IsNullOrWhiteSpace(input))
{
await ReplyErrorLocalizedAsync(strs.expr_import_no_input);
return;
}
}
var succ = await ImportCrsAsync(ctx.Guild.Id, input);
if (!succ)
{
await ReplyErrorLocalizedAsync(strs.expr_import_invalid_data);
return;
}
await ctx.OkAsync();
}
public async Task<bool> ImportCrsAsync(ulong guildId, string input)
{
Dictionary<string, List<ExportedQuote>> data;
try
{
data = Yaml.Deserializer.Deserialize<Dictionary<string, List<ExportedQuote>>>(input);
if (data.Sum(x => x.Value.Count) == 0)
return false;
}
catch
{
return false;
}
await using var uow = _db.GetDbContext();
foreach (var entry in data)
{
var keyword = entry.Key;
await uow.Quotes
.AddRangeAsync(entry.Value
.Where(quote => !string.IsNullOrWhiteSpace(quote.Txt))
.Select(quote => new Quote()
{
GuildId = guildId,
Keyword = keyword,
Text = quote.Txt,
AuthorId = quote.Aid,
AuthorName = quote.An,
}));
}
await uow.SaveChangesAsync();
return true;
}
}
}
}

View File

@@ -1265,3 +1265,9 @@ imageonlychannel:
- imagesonly
coordreload:
- coordreload
quotesexport:
- quotesexport
- qexport
quotesimport:
- quotesimport
- qimport

View File

@@ -1578,6 +1578,14 @@ crsexport:
desc: "Exports custom reactions from the current server (or global custom reactions in DMs) into a .yml file"
args:
- ""
quotesimport:
desc: "Upload the file or send the raw .yml data with this command to import all quotes from the specified string or file into the current server."
args:
- "<upload .yml file>"
quotesexport:
desc: "Exports quotes from the current server into a .yml file"
args:
- ""
aliaslist:
desc: "Shows the list of currently set aliases. Paginated."
args:
@@ -2068,7 +2076,7 @@ rollduel:
- "50 @Someone"
- "@Challenger"
reactionroles:
desc: "Specify role names and server emojis with which they're represented, the bot will then add those emojis to the previous message in the channel, and users will be able to get the roles by clicking on the emoji. You can set 'excl' as the parameter before the reactions and roles to make them exclusive. You can have up to 5 of these enabled on one server at a time. Optionally you can specify target message if you don't want it to be the previous one."
desc: "Specify role names and server emojis with which they're represented, the bot will then add those emojis to the previous message in the channel, and users will be able to get the roles by clicking on the emoji. You can set 'excl' as the parameter before the reactions and roles to make them exclusive. You can have up to 10 of these enabled on one server at a time. Optionally you can specify target message if you don't want it to be the previous one."
args:
- "Gamer :SomeServerEmoji: Streamer :Other: Watcher :Other2:"
- "excl Horde :Horde: Alliance :Alliance:"

View File

@@ -682,7 +682,7 @@
"clpa_obsolete": ":tada: **Patreon currency rewards are now automatic!** :tada:\nThis command is now obsolete.\nIf you did not receive your reward for this month's pledge, below are some of the reasons as to why that might be.",
"clpa_fail_already": "Maybe you've already received your reward for this month. You can receive rewards only once a month unless you increase your pledge.\nYou can check it by using `.curtrs` command.",
"clpa_fail_already_title": "Already rewarded",
"clpa_fail_conn": "Your discord account might not be connected to Patreon. If you are unsure what that means, or don't know how to connect it - you have to go to [Patreon account settings page](https://patreon.com/settings/account) and click 'Connect to discord' button.",
"clpa_fail_conn": "Your discord account might not be connected to Patreon. If you are unsure what that means, or don't know how to connect it - you have to go to [Patreon account settings page](https://www.patreon.com/settings/apps) and click 'Connect to discord' button.",
"clpa_fail_conn_title": "Discord account not connected",
"clpa_fail_sup": "In order to be eligible for the reward, you must support the project on patreon. You can use {0} command to get the link.",
"clpa_fail_sup_title": "Not supporting",