mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-11 01:38:27 -04:00
Fixed some aliases and reworked namespaces
This commit is contained in:
@@ -113,7 +113,7 @@ public partial class Administration : NadekoModule<AdministrationService>
|
||||
|
||||
embed.AddField(GetText(strs.channel_delmsgoncmd), str);
|
||||
|
||||
await ctx.Channel.EmbedAsync(embed);
|
||||
await EmbedAsync(embed);
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
|
@@ -1,8 +1,7 @@
|
||||
#nullable disable
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Common;
|
||||
using NadekoBot.Db;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#nullable disable
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
using System.Net;
|
||||
using System.Threading.Channels;
|
||||
using LinqToDB;
|
||||
|
@@ -2,119 +2,163 @@
|
||||
using System.Globalization;
|
||||
using CsvHelper;
|
||||
using CsvHelper.Configuration;
|
||||
using NadekoBot.Modules.Gambling;
|
||||
using NadekoBot.Modules.Administration.Services;
|
||||
using NadekoBot.Modules.Xp;
|
||||
|
||||
#if !GLOBAL_NADEKO
|
||||
namespace NadekoBot.Modules.Administration
|
||||
namespace NadekoBot.Modules.Administration;
|
||||
|
||||
public partial class Administration
|
||||
{
|
||||
public partial class Administration
|
||||
[Group]
|
||||
[OwnerOnly]
|
||||
[NoPublicBot]
|
||||
public partial class DangerousCommands : CleanupModuleBase
|
||||
{
|
||||
[Group]
|
||||
[OwnerOnly]
|
||||
public partial class DangerousCommands : NadekoModule<DangerousCommandsService>
|
||||
private readonly DangerousCommandsService _ds;
|
||||
private readonly IGamblingCleanupService _gcs;
|
||||
private readonly IXpCleanupService _xcs;
|
||||
|
||||
public DangerousCommands(
|
||||
DangerousCommandsService ds,
|
||||
IGamblingCleanupService gcs,
|
||||
IXpCleanupService xcs)
|
||||
{
|
||||
[Cmd]
|
||||
[OwnerOnly]
|
||||
public Task SqlSelect([Leftover] string sql)
|
||||
_ds = ds;
|
||||
_gcs = gcs;
|
||||
_xcs = xcs;
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[OwnerOnly]
|
||||
public Task SqlSelect([Leftover] string sql)
|
||||
{
|
||||
var result = _ds.SelectSql(sql);
|
||||
|
||||
return ctx.SendPaginatedConfirmAsync(0,
|
||||
cur =>
|
||||
{
|
||||
var items = result.Results.Skip(cur * 20).Take(20).ToList();
|
||||
|
||||
if (!items.Any())
|
||||
return _eb.Create().WithErrorColor().WithFooter(sql).WithDescription("-");
|
||||
|
||||
return _eb.Create()
|
||||
.WithOkColor()
|
||||
.WithFooter(sql)
|
||||
.WithTitle(string.Join(" ║ ", result.ColumnNames))
|
||||
.WithDescription(string.Join('\n', items.Select(x => string.Join(" ║ ", x))));
|
||||
},
|
||||
result.Results.Count,
|
||||
20);
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[OwnerOnly]
|
||||
public async Task SqlSelectCsv([Leftover] string sql)
|
||||
{
|
||||
var result = _ds.SelectSql(sql);
|
||||
|
||||
// create a file stream and write the data as csv
|
||||
using var ms = new MemoryStream();
|
||||
await using var sw = new StreamWriter(ms);
|
||||
await using var csv = new CsvWriter(sw,
|
||||
new CsvConfiguration(CultureInfo.InvariantCulture)
|
||||
{
|
||||
Delimiter = ","
|
||||
});
|
||||
|
||||
foreach (var cn in result.ColumnNames)
|
||||
{
|
||||
var result = _service.SelectSql(sql);
|
||||
|
||||
return ctx.SendPaginatedConfirmAsync(0,
|
||||
cur =>
|
||||
{
|
||||
var items = result.Results.Skip(cur * 20).Take(20).ToList();
|
||||
|
||||
if (!items.Any())
|
||||
return _eb.Create().WithErrorColor().WithFooter(sql).WithDescription("-");
|
||||
|
||||
return _eb.Create()
|
||||
.WithOkColor()
|
||||
.WithFooter(sql)
|
||||
.WithTitle(string.Join(" ║ ", result.ColumnNames))
|
||||
.WithDescription(string.Join('\n', items.Select(x => string.Join(" ║ ", x))));
|
||||
},
|
||||
result.Results.Count,
|
||||
20);
|
||||
csv.WriteField(cn);
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[OwnerOnly]
|
||||
public async Task SqlSelectCsv([Leftover] string sql)
|
||||
await csv.NextRecordAsync();
|
||||
|
||||
foreach (var row in result.Results)
|
||||
{
|
||||
var result = _service.SelectSql(sql);
|
||||
|
||||
// create a file stream and write the data as csv
|
||||
using var ms = new MemoryStream();
|
||||
await using var sw = new StreamWriter(ms);
|
||||
await using var csv = new CsvWriter(sw,
|
||||
new CsvConfiguration(CultureInfo.InvariantCulture) { Delimiter = "," });
|
||||
|
||||
foreach (var cn in result.ColumnNames)
|
||||
foreach (var field in row)
|
||||
{
|
||||
csv.WriteField(cn);
|
||||
csv.WriteField(field);
|
||||
}
|
||||
|
||||
await csv.NextRecordAsync();
|
||||
|
||||
foreach (var row in result.Results)
|
||||
{
|
||||
foreach (var field in row)
|
||||
{
|
||||
csv.WriteField(field);
|
||||
}
|
||||
|
||||
await csv.NextRecordAsync();
|
||||
}
|
||||
|
||||
|
||||
await csv.FlushAsync();
|
||||
ms.Position = 0;
|
||||
|
||||
// send the file
|
||||
await ctx.Channel.SendFileAsync(ms, $"query_result_{DateTime.UtcNow.Ticks}.csv");
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[OwnerOnly]
|
||||
public async Task SqlExec([Leftover] string sql)
|
||||
{
|
||||
try
|
||||
{
|
||||
var embed = _eb.Create()
|
||||
.WithTitle(GetText(strs.sql_confirm_exec))
|
||||
.WithDescription(Format.Code(sql));
|
||||
|
||||
if (!await PromptUserConfirmAsync(embed))
|
||||
return;
|
||||
await csv.FlushAsync();
|
||||
ms.Position = 0;
|
||||
|
||||
var res = await _service.ExecuteSql(sql);
|
||||
await SendConfirmAsync(res.ToString());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await SendErrorAsync(ex.ToString());
|
||||
}
|
||||
}
|
||||
// send the file
|
||||
await ctx.Channel.SendFileAsync(ms, $"query_result_{DateTime.UtcNow.Ticks}.csv");
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[OwnerOnly]
|
||||
public async Task PurgeUser(ulong userId)
|
||||
[Cmd]
|
||||
[OwnerOnly]
|
||||
public async Task SqlExec([Leftover] string sql)
|
||||
{
|
||||
try
|
||||
{
|
||||
var embed = _eb.Create()
|
||||
.WithDescription(GetText(strs.purge_user_confirm(Format.Bold(userId.ToString()))));
|
||||
.WithTitle(GetText(strs.sql_confirm_exec))
|
||||
.WithDescription(Format.Code(sql));
|
||||
|
||||
if (!await PromptUserConfirmAsync(embed))
|
||||
return;
|
||||
|
||||
await _service.PurgeUserAsync(userId);
|
||||
await ctx.OkAsync();
|
||||
var res = await _ds.ExecuteSql(sql);
|
||||
await SendConfirmAsync(res.ToString());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await SendErrorAsync(ex.ToString());
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[OwnerOnly]
|
||||
public Task PurgeUser([Leftover] IUser user)
|
||||
=> PurgeUser(user.Id);
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[OwnerOnly]
|
||||
public async Task PurgeUser(ulong userId)
|
||||
{
|
||||
var embed = _eb.Create()
|
||||
.WithDescription(GetText(strs.purge_user_confirm(Format.Bold(userId.ToString()))));
|
||||
|
||||
if (!await PromptUserConfirmAsync(embed))
|
||||
return;
|
||||
|
||||
await _ds.PurgeUserAsync(userId);
|
||||
await ctx.OkAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[OwnerOnly]
|
||||
public Task PurgeUser([Leftover] IUser user)
|
||||
=> PurgeUser(user.Id);
|
||||
|
||||
[Cmd]
|
||||
[OwnerOnly]
|
||||
public Task DeleteXp()
|
||||
=> ConfirmActionInternalAsync("Delete Xp", () => _xcs.DeleteXp());
|
||||
|
||||
|
||||
[Cmd]
|
||||
[OwnerOnly]
|
||||
public Task DeleteWaifus()
|
||||
=> ConfirmActionInternalAsync("Delete Waifus", () => _gcs.DeleteWaifus());
|
||||
|
||||
[Cmd]
|
||||
[OwnerOnly]
|
||||
public async Task DeleteWaifu(IUser user)
|
||||
=> await DeleteWaifu(user.Id);
|
||||
|
||||
[Cmd]
|
||||
[OwnerOnly]
|
||||
public Task DeleteWaifu(ulong userId)
|
||||
=> ConfirmActionInternalAsync($"Delete Waifu {userId}", () => _gcs.DeleteWaifu(userId));
|
||||
|
||||
|
||||
[Cmd]
|
||||
[OwnerOnly]
|
||||
public Task DeleteCurrency()
|
||||
=> ConfirmActionInternalAsync("Delete Currency", () => _gcs.DeleteCurrency());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
@@ -3,7 +3,6 @@ using LinqToDB;
|
||||
using LinqToDB.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Db.Models;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
|
||||
|
@@ -1,8 +1,7 @@
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Db;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
using System.Threading.Channels;
|
||||
using NadekoBot.Common;
|
||||
|
||||
namespace NadekoBot.Services;
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Services;
|
||||
|
||||
|
@@ -4,7 +4,7 @@ using Microsoft.Extensions.Caching.Memory;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using System.Net;
|
||||
using System.Threading.Channels;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
|
||||
|
@@ -112,7 +112,7 @@ public partial class Administration
|
||||
|
||||
[Cmd]
|
||||
public async Task LanguagesList()
|
||||
=> await ctx.Channel.EmbedAsync(_eb.Create()
|
||||
=> await EmbedAsync(_eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.lang_list))
|
||||
.WithDescription(string.Join("\n",
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#nullable disable
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Db;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
|
||||
|
@@ -1,8 +1,7 @@
|
||||
#nullable disable
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Common;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
|
||||
@@ -90,7 +89,7 @@ public sealed class PlayingRotateService : INService, IReadyExecutor
|
||||
var toAdd = new RotatingPlayingStatus
|
||||
{
|
||||
Status = status,
|
||||
Type = (Nadeko.Bot.Db.ActivityType)activityType
|
||||
Type = (NadekoBot.Db.DbActivityType)activityType
|
||||
};
|
||||
uow.Add(toAdd);
|
||||
await uow.SaveChangesAsync();
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Common.TypeReaders.Models;
|
||||
using NadekoBot.Modules.Administration.Services;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration;
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#nullable disable
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Db;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
using System.Threading.Channels;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#nullable disable
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration;
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#nullable disable
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration;
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Modules.Patronage;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
using OneOf;
|
||||
using OneOf.Types;
|
||||
|
||||
|
@@ -4,7 +4,7 @@ using LinqToDB.EntityFrameworkCore;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Db;
|
||||
using NadekoBot.Modules.Patronage;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
using OneOf.Types;
|
||||
using OneOf;
|
||||
|
||||
|
@@ -1,5 +1,4 @@
|
||||
#nullable disable
|
||||
using System.Xml.Schema;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using Color = SixLabors.ImageSharp.Color;
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#nullable disable
|
||||
using LinqToDB;
|
||||
using LinqToDB.EntityFrameworkCore;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Db;
|
||||
|
||||
|
@@ -1,7 +1,6 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Common;
|
||||
using NadekoBot.Modules.Administration.Services;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
using Nadeko.Common.Medusa;
|
||||
|
||||
namespace NadekoBot.Modules.Administration;
|
||||
@@ -113,7 +112,7 @@ public partial class Administration
|
||||
};
|
||||
_service.AddNewAutoCommand(cmd);
|
||||
|
||||
await ctx.Channel.EmbedAsync(_eb.Create()
|
||||
await EmbedAsync(_eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.scadd))
|
||||
.AddField(GetText(strs.server),
|
||||
|
@@ -1,11 +1,10 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
using System.Collections.Immutable;
|
||||
using LinqToDB;
|
||||
using LinqToDB.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#nullable disable
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Db;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration;
|
||||
|
||||
|
@@ -3,7 +3,7 @@ using Microsoft.Extensions.Caching.Memory;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Db;
|
||||
using NadekoBot.Modules.Administration.Services;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration;
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
using NadekoBot.Common.TypeReaders.Models;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration;
|
||||
|
||||
@@ -46,7 +46,7 @@ public partial class Administration
|
||||
? "-"
|
||||
: string.Join('\n', usrs.Select(x => $"{x.LogItemId} | <@{x.LogItemId}>")));
|
||||
|
||||
await ctx.Channel.EmbedAsync(eb);
|
||||
await EmbedAsync(eb);
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Db;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
|
@@ -3,7 +3,7 @@ using CommandLine;
|
||||
using Humanizer.Localisation;
|
||||
using NadekoBot.Common.TypeReaders.Models;
|
||||
using NadekoBot.Modules.Administration.Services;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration;
|
||||
|
||||
|
@@ -2,12 +2,11 @@
|
||||
using LinqToDB;
|
||||
using LinqToDB.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Common;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Common.TypeReaders.Models;
|
||||
using NadekoBot.Db;
|
||||
using NadekoBot.Modules.Permissions.Services;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
|
@@ -68,7 +68,7 @@ public partial class Administration
|
||||
else
|
||||
text = GetText(strs.no_vcroles);
|
||||
|
||||
await ctx.Channel.EmbedAsync(_eb.Create()
|
||||
await EmbedAsync(_eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.vc_role_list))
|
||||
.WithDescription(text));
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#nullable disable
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Db;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Services;
|
||||
|
||||
|
27
src/NadekoBot/Modules/Expressions/ExportedExpr.cs
Normal file
27
src/NadekoBot/Modules/Expressions/ExportedExpr.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.NadekoExpressions;
|
||||
|
||||
public class ExportedExpr
|
||||
{
|
||||
public string Res { get; set; }
|
||||
public string Id { get; set; }
|
||||
public bool Ad { get; set; }
|
||||
public bool Dm { get; set; }
|
||||
public bool At { get; set; }
|
||||
public bool Ca { get; set; }
|
||||
public string[] React;
|
||||
|
||||
public static ExportedExpr FromModel(NadekoExpression cr)
|
||||
=> new()
|
||||
{
|
||||
Res = cr.Response,
|
||||
Id = ((kwum)cr.Id).ToString(),
|
||||
Ad = cr.AutoDeleteTrigger,
|
||||
At = cr.AllowTarget,
|
||||
Ca = cr.ContainsAnywhere,
|
||||
Dm = cr.DmResponse,
|
||||
React = string.IsNullOrWhiteSpace(cr.Reactions) ? null : cr.GetReactions()
|
||||
};
|
||||
}
|
10
src/NadekoBot/Modules/Expressions/ExprField.cs
Normal file
10
src/NadekoBot/Modules/Expressions/ExprField.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace NadekoBot.Modules.NadekoExpressions;
|
||||
|
||||
public enum ExprField
|
||||
{
|
||||
AutoDelete,
|
||||
DmResponse,
|
||||
AllowTarget,
|
||||
ContainsAnywhere,
|
||||
Message
|
||||
}
|
@@ -0,0 +1,91 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Db.Models;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace NadekoBot.Modules.NadekoExpressions;
|
||||
|
||||
public static class NadekoExpressionExtensions
|
||||
{
|
||||
private static string ResolveTriggerString(this string str, DiscordSocketClient client)
|
||||
=> str.Replace("%bot.mention%", client.CurrentUser.Mention, StringComparison.Ordinal);
|
||||
|
||||
public static async Task<IUserMessage> Send(
|
||||
this NadekoExpression cr,
|
||||
IUserMessage ctx,
|
||||
IReplacementService repSvc,
|
||||
DiscordSocketClient client,
|
||||
bool sanitize)
|
||||
{
|
||||
var channel = cr.DmResponse ? await ctx.Author.CreateDMChannelAsync() : ctx.Channel;
|
||||
|
||||
var trigger = cr.Trigger.ResolveTriggerString(client);
|
||||
var substringIndex = trigger.Length;
|
||||
if (cr.ContainsAnywhere)
|
||||
{
|
||||
var pos = ctx.Content.AsSpan().GetWordPosition(trigger);
|
||||
if (pos == WordPosition.Start)
|
||||
substringIndex += 1;
|
||||
else if (pos == WordPosition.End)
|
||||
substringIndex = ctx.Content.Length;
|
||||
else if (pos == WordPosition.Middle)
|
||||
substringIndex += ctx.Content.IndexOf(trigger, StringComparison.InvariantCulture);
|
||||
}
|
||||
|
||||
var canMentionEveryone = (ctx.Author as IGuildUser)?.GuildPermissions.MentionEveryone ?? true;
|
||||
|
||||
var repCtx = new ReplacementContext(client: client,
|
||||
guild: (ctx.Channel as ITextChannel)?.Guild as SocketGuild,
|
||||
channel: ctx.Channel,
|
||||
users: ctx.Author
|
||||
)
|
||||
.WithOverride("%target%",
|
||||
() => canMentionEveryone
|
||||
? ctx.Content[substringIndex..].Trim()
|
||||
: ctx.Content[substringIndex..].Trim().SanitizeMentions(true));
|
||||
|
||||
var text = SmartText.CreateFrom(cr.Response);
|
||||
text = await repSvc.ReplaceAsync(text, repCtx);
|
||||
|
||||
return await channel.SendAsync(text, sanitize);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static WordPosition GetWordPosition(this ReadOnlySpan<char> str, in ReadOnlySpan<char> word)
|
||||
{
|
||||
var wordIndex = str.IndexOf(word, StringComparison.OrdinalIgnoreCase);
|
||||
if (wordIndex == -1)
|
||||
return WordPosition.None;
|
||||
|
||||
if (wordIndex == 0)
|
||||
{
|
||||
if (word.Length < str.Length && str.IsValidWordDivider(word.Length))
|
||||
return WordPosition.Start;
|
||||
}
|
||||
else if (wordIndex + word.Length == str.Length)
|
||||
{
|
||||
if (str.IsValidWordDivider(wordIndex - 1))
|
||||
return WordPosition.End;
|
||||
}
|
||||
else if (str.IsValidWordDivider(wordIndex - 1) && str.IsValidWordDivider(wordIndex + word.Length))
|
||||
return WordPosition.Middle;
|
||||
|
||||
return WordPosition.None;
|
||||
}
|
||||
|
||||
private static bool IsValidWordDivider(this in ReadOnlySpan<char> str, int index)
|
||||
{
|
||||
var ch = str[index];
|
||||
if (ch is >= 'a' and <= 'z' or >= 'A' and <= 'Z' or >= '1' and <= '9')
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public enum WordPosition
|
||||
{
|
||||
None,
|
||||
Start,
|
||||
Middle,
|
||||
End
|
||||
}
|
393
src/NadekoBot/Modules/Expressions/NadekoExpressions.cs
Normal file
393
src/NadekoBot/Modules/Expressions/NadekoExpressions.cs
Normal file
@@ -0,0 +1,393 @@
|
||||
#nullable disable
|
||||
|
||||
namespace NadekoBot.Modules.NadekoExpressions;
|
||||
|
||||
[Name("Expressions")]
|
||||
public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
||||
{
|
||||
public enum All
|
||||
{
|
||||
All
|
||||
}
|
||||
|
||||
private readonly IBotCredentials _creds;
|
||||
private readonly IHttpClientFactory _clientFactory;
|
||||
|
||||
public NadekoExpressions(IBotCredentials creds, IHttpClientFactory clientFactory)
|
||||
{
|
||||
_creds = creds;
|
||||
_clientFactory = clientFactory;
|
||||
}
|
||||
|
||||
private bool AdminInGuildOrOwnerInDm()
|
||||
=> (ctx.Guild is null && _creds.IsOwner(ctx.User))
|
||||
|| (ctx.Guild is not null && ((IGuildUser)ctx.User).GuildPermissions.Administrator);
|
||||
|
||||
private async Task ExprAddInternalAsync(string key, string message)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(message) || string.IsNullOrWhiteSpace(key))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var ex = await _service.AddAsync(ctx.Guild?.Id, key, message);
|
||||
|
||||
await EmbedAsync(_eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.expr_new))
|
||||
.WithDescription($"#{new kwum(ex.Id)}")
|
||||
.AddField(GetText(strs.trigger), key)
|
||||
.AddField(GetText(strs.response),
|
||||
message.Length > 1024 ? GetText(strs.redacted_too_long) : message));
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
public async Task ExprToggleGlobal()
|
||||
{
|
||||
var result = await _service.ToggleGlobalExpressionsAsync(ctx.Guild.Id);
|
||||
if (result)
|
||||
await ReplyConfirmLocalizedAsync(strs.expr_global_disabled);
|
||||
else
|
||||
await ReplyConfirmLocalizedAsync(strs.expr_global_enabled);
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
public async Task ExprAddServer(string key, [Leftover] string message)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(message) || string.IsNullOrWhiteSpace(key))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await ExprAddInternalAsync(key, message);
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
public async Task ExprAdd(string key, [Leftover] string message)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(message) || string.IsNullOrWhiteSpace(key))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!AdminInGuildOrOwnerInDm())
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.expr_insuff_perms);
|
||||
return;
|
||||
}
|
||||
|
||||
await ExprAddInternalAsync(key, message);
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
public async Task ExprEdit(kwum id, [Leftover] string message)
|
||||
{
|
||||
var channel = ctx.Channel as ITextChannel;
|
||||
if (string.IsNullOrWhiteSpace(message) || id < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ((channel is null && !_creds.IsOwner(ctx.User))
|
||||
|| (channel is not null && !((IGuildUser)ctx.User).GuildPermissions.Administrator))
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.expr_insuff_perms);
|
||||
return;
|
||||
}
|
||||
|
||||
var ex = await _service.EditAsync(ctx.Guild?.Id, id, message);
|
||||
if (ex is not null)
|
||||
{
|
||||
await ctx.Channel.EmbedAsync(_eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.expr_edited))
|
||||
.WithDescription($"#{id}")
|
||||
.AddField(GetText(strs.trigger), ex.Trigger)
|
||||
.AddField(GetText(strs.response),
|
||||
message.Length > 1024 ? GetText(strs.redacted_too_long) : message));
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.expr_no_found_id);
|
||||
}
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[Priority(1)]
|
||||
public async Task ExprList(int page = 1)
|
||||
{
|
||||
if (--page < 0 || page > 999)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var expressions = _service.GetExpressionsFor(ctx.Guild?.Id);
|
||||
|
||||
if (expressions is null || !expressions.Any())
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.expr_no_found);
|
||||
return;
|
||||
}
|
||||
|
||||
await ctx.SendPaginatedConfirmAsync(page,
|
||||
curPage =>
|
||||
{
|
||||
var desc = expressions.OrderBy(ex => ex.Trigger)
|
||||
.Skip(curPage * 20)
|
||||
.Take(20)
|
||||
.Select(ex => $"{(ex.ContainsAnywhere ? "🗯" : "◾")}"
|
||||
+ $"{(ex.DmResponse ? "✉" : "◾")}"
|
||||
+ $"{(ex.AutoDeleteTrigger ? "❌" : "◾")}"
|
||||
+ $"`{(kwum)ex.Id}` {ex.Trigger}"
|
||||
+ (string.IsNullOrWhiteSpace(ex.Reactions)
|
||||
? string.Empty
|
||||
: " // " + string.Join(" ", ex.GetReactions())))
|
||||
.Join('\n');
|
||||
|
||||
return _eb.Create().WithOkColor().WithTitle(GetText(strs.expressions)).WithDescription(desc);
|
||||
},
|
||||
expressions.Length,
|
||||
20);
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
public async Task ExprShow(kwum id)
|
||||
{
|
||||
var found = _service.GetExpression(ctx.Guild?.Id, id);
|
||||
|
||||
if (found is null)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.expr_no_found_id);
|
||||
return;
|
||||
}
|
||||
|
||||
await ctx.Channel.EmbedAsync(_eb.Create()
|
||||
.WithOkColor()
|
||||
.WithDescription($"#{id}")
|
||||
.AddField(GetText(strs.trigger), found.Trigger.TrimTo(1024))
|
||||
.AddField(GetText(strs.response),
|
||||
found.Response.TrimTo(1000).Replace("](", "]\\(")));
|
||||
}
|
||||
|
||||
public async Task ExprDeleteInternalAsync(kwum id)
|
||||
{
|
||||
var ex = await _service.DeleteAsync(ctx.Guild?.Id, id);
|
||||
|
||||
if (ex is not null)
|
||||
{
|
||||
await ctx.Channel.EmbedAsync(_eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.expr_deleted))
|
||||
.WithDescription($"#{id}")
|
||||
.AddField(GetText(strs.trigger), ex.Trigger.TrimTo(1024))
|
||||
.AddField(GetText(strs.response), ex.Response.TrimTo(1024)));
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.expr_no_found_id);
|
||||
}
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task ExprDeleteServer(kwum id)
|
||||
=> await ExprDeleteInternalAsync(id);
|
||||
|
||||
[Cmd]
|
||||
public async Task ExprDelete(kwum id)
|
||||
{
|
||||
if (!AdminInGuildOrOwnerInDm())
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.expr_insuff_perms);
|
||||
return;
|
||||
}
|
||||
|
||||
await ExprDeleteInternalAsync(id);
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
public async Task ExprReact(kwum id, params string[] emojiStrs)
|
||||
{
|
||||
if (!AdminInGuildOrOwnerInDm())
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.expr_insuff_perms);
|
||||
return;
|
||||
}
|
||||
|
||||
var ex = _service.GetExpression(ctx.Guild?.Id, id);
|
||||
if (ex is null)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.expr_no_found_id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (emojiStrs.Length == 0)
|
||||
{
|
||||
await _service.ResetExprReactions(ctx.Guild?.Id, id);
|
||||
await ReplyConfirmLocalizedAsync(strs.expr_reset(Format.Bold(id.ToString())));
|
||||
return;
|
||||
}
|
||||
|
||||
var succ = new List<string>();
|
||||
foreach (var emojiStr in emojiStrs)
|
||||
{
|
||||
var emote = emojiStr.ToIEmote();
|
||||
|
||||
// i should try adding these emojis right away to the message, to make sure the bot can react with these emojis. If it fails, skip that emoji
|
||||
try
|
||||
{
|
||||
await ctx.Message.AddReactionAsync(emote);
|
||||
await Task.Delay(100);
|
||||
succ.Add(emojiStr);
|
||||
|
||||
if (succ.Count >= 3)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
if (succ.Count == 0)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.invalid_emojis);
|
||||
return;
|
||||
}
|
||||
|
||||
await _service.SetExprReactions(ctx.Guild?.Id, id, succ);
|
||||
|
||||
|
||||
await ReplyConfirmLocalizedAsync(strs.expr_set(Format.Bold(id.ToString()),
|
||||
succ.Select(static x => x.ToString()).Join(", ")));
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
public Task ExprCa(kwum id)
|
||||
=> InternalExprEdit(id, ExprField.ContainsAnywhere);
|
||||
|
||||
[Cmd]
|
||||
public Task ExprDm(kwum id)
|
||||
=> InternalExprEdit(id, ExprField.DmResponse);
|
||||
|
||||
[Cmd]
|
||||
public Task ExprAd(kwum id)
|
||||
=> InternalExprEdit(id, ExprField.AutoDelete);
|
||||
|
||||
[Cmd]
|
||||
public Task ExprAt(kwum id)
|
||||
=> InternalExprEdit(id, ExprField.AllowTarget);
|
||||
|
||||
[Cmd]
|
||||
[OwnerOnly]
|
||||
public async Task ExprsReload()
|
||||
{
|
||||
await _service.TriggerReloadExpressions();
|
||||
|
||||
await ctx.OkAsync();
|
||||
}
|
||||
|
||||
private async Task InternalExprEdit(kwum id, ExprField option)
|
||||
{
|
||||
if (!AdminInGuildOrOwnerInDm())
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.expr_insuff_perms);
|
||||
return;
|
||||
}
|
||||
|
||||
var (success, newVal) = await _service.ToggleExprOptionAsync(ctx.Guild?.Id, id, option);
|
||||
if (!success)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.expr_no_found_id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (newVal)
|
||||
{
|
||||
await ReplyConfirmLocalizedAsync(strs.option_enabled(Format.Code(option.ToString()),
|
||||
Format.Code(id.ToString())));
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyConfirmLocalizedAsync(strs.option_disabled(Format.Code(option.ToString()),
|
||||
Format.Code(id.ToString())));
|
||||
}
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
public async Task ExprClear()
|
||||
{
|
||||
if (await PromptUserConfirmAsync(_eb.Create()
|
||||
.WithTitle("Expression clear")
|
||||
.WithDescription("This will delete all expressions on this server.")))
|
||||
{
|
||||
var count = _service.DeleteAllExpressions(ctx.Guild.Id);
|
||||
await ReplyConfirmLocalizedAsync(strs.exprs_cleared(count));
|
||||
}
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
public async Task ExprsExport()
|
||||
{
|
||||
if (!AdminInGuildOrOwnerInDm())
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.expr_insuff_perms);
|
||||
return;
|
||||
}
|
||||
|
||||
_ = ctx.Channel.TriggerTypingAsync();
|
||||
|
||||
var serialized = _service.ExportExpressions(ctx.Guild?.Id);
|
||||
await using var stream = await serialized.ToStream();
|
||||
await ctx.Channel.SendFileAsync(stream, "exprs-export.yml");
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
#if GLOBAL_NADEKO
|
||||
[OwnerOnly]
|
||||
#endif
|
||||
public async Task ExprsImport([Leftover] string input = null)
|
||||
{
|
||||
if (!AdminInGuildOrOwnerInDm())
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.expr_insuff_perms);
|
||||
return;
|
||||
}
|
||||
|
||||
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 = _clientFactory.CreateClient();
|
||||
input = await client.GetStringAsync(attachment.Url);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(input))
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.expr_import_no_input);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var succ = await _service.ImportExpressionsAsync(ctx.Guild?.Id, input);
|
||||
if (!succ)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.expr_import_invalid_data);
|
||||
return;
|
||||
}
|
||||
|
||||
await ctx.OkAsync();
|
||||
}
|
||||
}
|
774
src/NadekoBot/Modules/Expressions/NadekoExpressionsService.cs
Normal file
774
src/NadekoBot/Modules/Expressions/NadekoExpressionsService.cs
Normal file
@@ -0,0 +1,774 @@
|
||||
#nullable disable
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Common.Yml;
|
||||
using NadekoBot.Db;
|
||||
using NadekoBot.Db.Models;
|
||||
using System.Runtime.CompilerServices;
|
||||
using LinqToDB.EntityFrameworkCore;
|
||||
using YamlDotNet.Serialization;
|
||||
using YamlDotNet.Serialization.NamingConventions;
|
||||
|
||||
namespace NadekoBot.Modules.NadekoExpressions;
|
||||
|
||||
public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
|
||||
{
|
||||
private const string MENTION_PH = "%bot.mention%";
|
||||
|
||||
private const string PREPEND_EXPORT =
|
||||
"""
|
||||
# Keys are triggers, Each key has a LIST of expressions in the following format:
|
||||
# - res: Response string
|
||||
# id: Alphanumeric id used for commands related to the expression. (Note, when using .exprsimport, a new id will be generated.)
|
||||
# react:
|
||||
# - <List
|
||||
# - of
|
||||
# - reactions>
|
||||
# at: Whether expression allows targets (see .h .exprat)
|
||||
# ca: Whether expression expects trigger anywhere (see .h .exprca)
|
||||
# dm: Whether expression DMs the response (see .h .exprdm)
|
||||
# ad: Whether expression automatically deletes triggering message (see .h .exprad)
|
||||
|
||||
|
||||
""";
|
||||
|
||||
private static readonly ISerializer _exportSerializer = new SerializerBuilder()
|
||||
.WithEventEmitter(args
|
||||
=> new MultilineScalarFlowStyleEmitter(args))
|
||||
.WithNamingConvention(CamelCaseNamingConvention.Instance)
|
||||
.WithIndentedSequences()
|
||||
.ConfigureDefaultValuesHandling(DefaultValuesHandling
|
||||
.OmitDefaults)
|
||||
.DisableAliases()
|
||||
.Build();
|
||||
|
||||
public int Priority
|
||||
=> 0;
|
||||
|
||||
private readonly object _gexprWriteLock = new();
|
||||
|
||||
private readonly TypedKey<NadekoExpression> _gexprAddedKey = new("gexpr.added");
|
||||
private readonly TypedKey<int> _gexprDeletedkey = new("gexpr.deleted");
|
||||
private readonly TypedKey<NadekoExpression> _gexprEditedKey = new("gexpr.edited");
|
||||
private readonly TypedKey<bool> _exprsReloadedKey = new("exprs.reloaded");
|
||||
|
||||
// it is perfectly fine to have global expressions as an array
|
||||
// 1. expressions are almost never added (compared to how many times they are being looped through)
|
||||
// 2. only need write locks for this as we'll rebuild+replace the array on every edit
|
||||
// 3. there's never many of them (at most a thousand, usually < 100)
|
||||
private NadekoExpression[] globalExpressions = Array.Empty<NadekoExpression>();
|
||||
private ConcurrentDictionary<ulong, NadekoExpression[]> newguildExpressions = new();
|
||||
|
||||
private readonly DbService _db;
|
||||
|
||||
private readonly DiscordSocketClient _client;
|
||||
|
||||
// private readonly PermissionService _perms;
|
||||
// private readonly GlobalPermissionService _gperm;
|
||||
// private readonly CmdCdService _cmdCds;
|
||||
private readonly IPermissionChecker _permChecker;
|
||||
private readonly ICommandHandler _cmd;
|
||||
private readonly IBotStrings _strings;
|
||||
private readonly IBot _bot;
|
||||
private readonly IPubSub _pubSub;
|
||||
private readonly IEmbedBuilderService _eb;
|
||||
private readonly IReplacementService _repSvc;
|
||||
private readonly Random _rng;
|
||||
|
||||
private bool ready;
|
||||
private ConcurrentHashSet<ulong> _disabledGlobalExpressionGuilds;
|
||||
|
||||
public NadekoExpressionsService(
|
||||
DbService db,
|
||||
IBotStrings strings,
|
||||
IBot bot,
|
||||
DiscordSocketClient client,
|
||||
ICommandHandler cmd,
|
||||
IPubSub pubSub,
|
||||
IEmbedBuilderService eb,
|
||||
IReplacementService repSvc,
|
||||
IPermissionChecker permChecker)
|
||||
{
|
||||
_db = db;
|
||||
_client = client;
|
||||
_cmd = cmd;
|
||||
_strings = strings;
|
||||
_bot = bot;
|
||||
_pubSub = pubSub;
|
||||
_eb = eb;
|
||||
_repSvc = repSvc;
|
||||
_permChecker = permChecker;
|
||||
_rng = new NadekoRandom();
|
||||
|
||||
_pubSub.Sub(_exprsReloadedKey, OnExprsShouldReload);
|
||||
pubSub.Sub(_gexprAddedKey, OnGexprAdded);
|
||||
pubSub.Sub(_gexprDeletedkey, OnGexprDeleted);
|
||||
pubSub.Sub(_gexprEditedKey, OnGexprEdited);
|
||||
|
||||
bot.JoinedGuild += OnJoinedGuild;
|
||||
_client.LeftGuild += OnLeftGuild;
|
||||
}
|
||||
|
||||
private async Task ReloadInternal(IReadOnlyList<ulong> allGuildIds)
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
var guildItems = await uow.Set<NadekoExpression>().AsNoTracking()
|
||||
.Where(x => allGuildIds.Contains(x.GuildId.Value))
|
||||
.ToListAsync();
|
||||
|
||||
newguildExpressions = guildItems.GroupBy(k => k.GuildId!.Value)
|
||||
.ToDictionary(g => g.Key,
|
||||
g => g.Select(x =>
|
||||
{
|
||||
x.Trigger = x.Trigger.Replace(MENTION_PH, _client.CurrentUser.Mention);
|
||||
return x;
|
||||
})
|
||||
.ToArray())
|
||||
.ToConcurrent();
|
||||
|
||||
_disabledGlobalExpressionGuilds = new(await uow.Set<GuildConfig>()
|
||||
.Where(x => x.DisableGlobalExpressions)
|
||||
.Select(x => x.GuildId)
|
||||
.ToListAsyncLinqToDB());
|
||||
|
||||
lock (_gexprWriteLock)
|
||||
{
|
||||
var globalItems = uow.Set<NadekoExpression>().AsNoTracking()
|
||||
.Where(x => x.GuildId == null || x.GuildId == 0)
|
||||
.AsEnumerable()
|
||||
.Select(x =>
|
||||
{
|
||||
x.Trigger = x.Trigger.Replace(MENTION_PH, _client.CurrentUser.Mention);
|
||||
return x;
|
||||
})
|
||||
.ToArray();
|
||||
|
||||
globalExpressions = globalItems;
|
||||
}
|
||||
|
||||
ready = true;
|
||||
}
|
||||
|
||||
private NadekoExpression TryGetExpression(IUserMessage umsg)
|
||||
{
|
||||
if (!ready)
|
||||
return null;
|
||||
|
||||
if (umsg.Channel is not SocketTextChannel channel)
|
||||
return null;
|
||||
|
||||
var content = umsg.Content.Trim().ToLowerInvariant();
|
||||
|
||||
if (newguildExpressions.TryGetValue(channel.Guild.Id, out var expressions) && expressions.Length > 0)
|
||||
{
|
||||
var expr = MatchExpressions(content, expressions);
|
||||
if (expr is not null)
|
||||
return expr;
|
||||
}
|
||||
|
||||
if (_disabledGlobalExpressionGuilds.Contains(channel.Guild.Id))
|
||||
return null;
|
||||
|
||||
var localGrs = globalExpressions;
|
||||
|
||||
return MatchExpressions(content, localGrs);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private NadekoExpression MatchExpressions(in ReadOnlySpan<char> content, NadekoExpression[] exprs)
|
||||
{
|
||||
var result = new List<NadekoExpression>(1);
|
||||
for (var i = 0; i < exprs.Length; i++)
|
||||
{
|
||||
var expr = exprs[i];
|
||||
var trigger = expr.Trigger;
|
||||
if (content.Length > trigger.Length)
|
||||
{
|
||||
// if input is greater than the trigger, it can only work if:
|
||||
// it has CA enabled
|
||||
if (expr.ContainsAnywhere)
|
||||
{
|
||||
// if ca is enabled, we have to check if it is a word within the content
|
||||
var wp = content.GetWordPosition(trigger);
|
||||
|
||||
// if it is, then that's valid
|
||||
if (wp != WordPosition.None)
|
||||
result.Add(expr);
|
||||
|
||||
// if it's not, then it cant' work under any circumstance,
|
||||
// because content is greater than the trigger length
|
||||
// so it can't be equal, and it's not contained as a word
|
||||
continue;
|
||||
}
|
||||
|
||||
// if CA is disabled, and expr has AllowTarget, then the
|
||||
// content has to start with the trigger followed by a space
|
||||
if (expr.AllowTarget
|
||||
&& content.StartsWith(trigger, StringComparison.OrdinalIgnoreCase)
|
||||
&& content[trigger.Length] == ' ')
|
||||
result.Add(expr);
|
||||
}
|
||||
else if (content.Length < expr.Trigger.Length)
|
||||
{
|
||||
// if input length is less than trigger length, it means
|
||||
// that the reaction can never be triggered
|
||||
}
|
||||
else
|
||||
{
|
||||
// if input length is the same as trigger length
|
||||
// reaction can only trigger if the strings are equal
|
||||
if (content.SequenceEqual(expr.Trigger))
|
||||
result.Add(expr);
|
||||
}
|
||||
}
|
||||
|
||||
if (result.Count == 0)
|
||||
return null;
|
||||
|
||||
var cancelled = result.FirstOrDefault(x => x.Response == "-");
|
||||
if (cancelled is not null)
|
||||
return cancelled;
|
||||
|
||||
return result[_rng.Next(0, result.Count)];
|
||||
}
|
||||
|
||||
public async Task<bool> ExecOnMessageAsync(IGuild guild, IUserMessage msg)
|
||||
{
|
||||
// maybe this message is an expression
|
||||
var expr = TryGetExpression(msg);
|
||||
|
||||
if (expr is null || expr.Response == "-")
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
if (guild is SocketGuild sg)
|
||||
{
|
||||
var result = await _permChecker.CheckPermsAsync(
|
||||
guild,
|
||||
msg.Channel,
|
||||
msg.Author,
|
||||
"ACTUALEXPRESSIONS",
|
||||
expr.Trigger
|
||||
);
|
||||
|
||||
if (!result.IsAllowed)
|
||||
{
|
||||
if (result.TryPickT3(out var disallowed, out _))
|
||||
{
|
||||
var permissionMessage = _strings.GetText(strs.perm_prevent(disallowed.PermIndex + 1,
|
||||
Format.Bold(disallowed.PermText)),
|
||||
sg.Id);
|
||||
|
||||
try
|
||||
{
|
||||
await msg.Channel.SendErrorAsync(_eb, permissionMessage);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
Log.Information("{PermissionMessage}", permissionMessage);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
var sentMsg = await expr.Send(msg, _repSvc, _client, false);
|
||||
|
||||
var reactions = expr.GetReactions();
|
||||
foreach (var reaction in reactions)
|
||||
{
|
||||
try
|
||||
{
|
||||
await sentMsg.AddReactionAsync(reaction.ToIEmote());
|
||||
}
|
||||
catch
|
||||
{
|
||||
Log.Warning("Unable to add reactions to message {Message} in server {GuildId}",
|
||||
sentMsg.Id,
|
||||
expr.GuildId);
|
||||
break;
|
||||
}
|
||||
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
|
||||
if (expr.AutoDeleteTrigger)
|
||||
{
|
||||
try
|
||||
{
|
||||
await msg.DeleteAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
Log.Information("s: {GuildId} c: {ChannelId} u: {UserId} | {UserName} executed expression {Expr}",
|
||||
guild.Id,
|
||||
msg.Channel.Id,
|
||||
msg.Author.Id,
|
||||
msg.Author.ToString(),
|
||||
expr.Trigger);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warning(ex, "Error in Expression RunBehavior: {ErrorMessage}", ex.Message);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public async Task ResetExprReactions(ulong? maybeGuildId, int id)
|
||||
{
|
||||
NadekoExpression expr;
|
||||
await using var uow = _db.GetDbContext();
|
||||
expr = uow.Set<NadekoExpression>().GetById(id);
|
||||
if (expr is null)
|
||||
return;
|
||||
|
||||
expr.Reactions = string.Empty;
|
||||
|
||||
await uow.SaveChangesAsync();
|
||||
}
|
||||
|
||||
private Task UpdateInternalAsync(ulong? maybeGuildId, NadekoExpression expr)
|
||||
{
|
||||
if (maybeGuildId is { } guildId)
|
||||
UpdateInternal(guildId, expr);
|
||||
else
|
||||
return _pubSub.Pub(_gexprEditedKey, expr);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private void UpdateInternal(ulong? maybeGuildId, NadekoExpression expr)
|
||||
{
|
||||
if (maybeGuildId is { } guildId)
|
||||
{
|
||||
newguildExpressions.AddOrUpdate(guildId,
|
||||
new[] { expr },
|
||||
(_, old) =>
|
||||
{
|
||||
var newArray = old.ToArray();
|
||||
for (var i = 0; i < newArray.Length; i++)
|
||||
{
|
||||
if (newArray[i].Id == expr.Id)
|
||||
newArray[i] = expr;
|
||||
}
|
||||
|
||||
return newArray;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
lock (_gexprWriteLock)
|
||||
{
|
||||
var exprs = globalExpressions;
|
||||
for (var i = 0; i < exprs.Length; i++)
|
||||
{
|
||||
if (exprs[i].Id == expr.Id)
|
||||
exprs[i] = expr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Task AddInternalAsync(ulong? maybeGuildId, NadekoExpression expr)
|
||||
{
|
||||
// only do this for perf purposes
|
||||
expr.Trigger = expr.Trigger.Replace(MENTION_PH, _client.CurrentUser.Mention);
|
||||
|
||||
if (maybeGuildId is { } guildId)
|
||||
newguildExpressions.AddOrUpdate(guildId, new[] { expr }, (_, old) => old.With(expr));
|
||||
else
|
||||
return _pubSub.Pub(_gexprAddedKey, expr);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private Task DeleteInternalAsync(ulong? maybeGuildId, int id)
|
||||
{
|
||||
if (maybeGuildId is { } guildId)
|
||||
{
|
||||
newguildExpressions.AddOrUpdate(guildId,
|
||||
Array.Empty<NadekoExpression>(),
|
||||
(key, old) => DeleteInternal(old, id, out _));
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
lock (_gexprWriteLock)
|
||||
{
|
||||
var expr = Array.Find(globalExpressions, item => item.Id == id);
|
||||
if (expr is not null)
|
||||
return _pubSub.Pub(_gexprDeletedkey, expr.Id);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private NadekoExpression[] DeleteInternal(
|
||||
IReadOnlyList<NadekoExpression> exprs,
|
||||
int id,
|
||||
out NadekoExpression deleted)
|
||||
{
|
||||
deleted = null;
|
||||
if (exprs is null || exprs.Count == 0)
|
||||
return exprs as NadekoExpression[] ?? exprs?.ToArray();
|
||||
|
||||
var newExprs = new NadekoExpression[exprs.Count - 1];
|
||||
for (int i = 0, k = 0; i < exprs.Count; i++, k++)
|
||||
{
|
||||
if (exprs[i].Id == id)
|
||||
{
|
||||
deleted = exprs[i];
|
||||
k--;
|
||||
continue;
|
||||
}
|
||||
|
||||
newExprs[k] = exprs[i];
|
||||
}
|
||||
|
||||
return newExprs;
|
||||
}
|
||||
|
||||
public async Task SetExprReactions(ulong? guildId, int id, IEnumerable<string> emojis)
|
||||
{
|
||||
NadekoExpression expr;
|
||||
await using (var uow = _db.GetDbContext())
|
||||
{
|
||||
expr = uow.Set<NadekoExpression>().GetById(id);
|
||||
if (expr is null)
|
||||
return;
|
||||
|
||||
expr.Reactions = string.Join("@@@", emojis);
|
||||
|
||||
await uow.SaveChangesAsync();
|
||||
}
|
||||
|
||||
await UpdateInternalAsync(guildId, expr);
|
||||
}
|
||||
|
||||
public async Task<(bool Sucess, bool NewValue)> ToggleExprOptionAsync(ulong? guildId, int id, ExprField field)
|
||||
{
|
||||
var newVal = false;
|
||||
NadekoExpression expr;
|
||||
await using (var uow = _db.GetDbContext())
|
||||
{
|
||||
expr = uow.Set<NadekoExpression>().GetById(id);
|
||||
|
||||
if (expr is null || expr.GuildId != guildId)
|
||||
return (false, false);
|
||||
if (field == ExprField.AutoDelete)
|
||||
newVal = expr.AutoDeleteTrigger = !expr.AutoDeleteTrigger;
|
||||
else if (field == ExprField.ContainsAnywhere)
|
||||
newVal = expr.ContainsAnywhere = !expr.ContainsAnywhere;
|
||||
else if (field == ExprField.DmResponse)
|
||||
newVal = expr.DmResponse = !expr.DmResponse;
|
||||
else if (field == ExprField.AllowTarget)
|
||||
newVal = expr.AllowTarget = !expr.AllowTarget;
|
||||
|
||||
await uow.SaveChangesAsync();
|
||||
}
|
||||
|
||||
await UpdateInternalAsync(guildId, expr);
|
||||
|
||||
return (true, newVal);
|
||||
}
|
||||
|
||||
public NadekoExpression GetExpression(ulong? guildId, int id)
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
var expr = uow.Set<NadekoExpression>().GetById(id);
|
||||
if (expr is null || expr.GuildId != guildId)
|
||||
return null;
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
public int DeleteAllExpressions(ulong guildId)
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
var count = uow.Set<NadekoExpression>().ClearFromGuild(guildId);
|
||||
uow.SaveChanges();
|
||||
|
||||
newguildExpressions.TryRemove(guildId, out _);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
public bool ExpressionExists(ulong? guildId, string input)
|
||||
{
|
||||
input = input.ToLowerInvariant();
|
||||
|
||||
var gexprs = globalExpressions;
|
||||
foreach (var t in gexprs)
|
||||
{
|
||||
if (t.Trigger == input)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (guildId is ulong gid && newguildExpressions.TryGetValue(gid, out var guildExprs))
|
||||
{
|
||||
foreach (var t in guildExprs)
|
||||
{
|
||||
if (t.Trigger == input)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public string ExportExpressions(ulong? guildId)
|
||||
{
|
||||
var exprs = GetExpressionsFor(guildId);
|
||||
|
||||
var exprsDict = exprs.GroupBy(x => x.Trigger).ToDictionary(x => x.Key, x => x.Select(ExportedExpr.FromModel));
|
||||
|
||||
return PREPEND_EXPORT + _exportSerializer.Serialize(exprsDict).UnescapeUnicodeCodePoints();
|
||||
}
|
||||
|
||||
public async Task<bool> ImportExpressionsAsync(ulong? guildId, string input)
|
||||
{
|
||||
Dictionary<string, List<ExportedExpr>> data;
|
||||
try
|
||||
{
|
||||
data = Yaml.Deserializer.Deserialize<Dictionary<string, List<ExportedExpr>>>(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 trigger = entry.Key;
|
||||
await uow.Set<NadekoExpression>().AddRangeAsync(entry.Value
|
||||
.Where(expr => !string.IsNullOrWhiteSpace(expr.Res))
|
||||
.Select(expr => new NadekoExpression
|
||||
{
|
||||
GuildId = guildId,
|
||||
Response = expr.Res,
|
||||
Reactions = expr.React?.Join("@@@"),
|
||||
Trigger = trigger,
|
||||
AllowTarget = expr.At,
|
||||
ContainsAnywhere = expr.Ca,
|
||||
DmResponse = expr.Dm,
|
||||
AutoDeleteTrigger = expr.Ad
|
||||
}));
|
||||
}
|
||||
|
||||
await uow.SaveChangesAsync();
|
||||
await TriggerReloadExpressions();
|
||||
return true;
|
||||
}
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
public async Task OnReadyAsync()
|
||||
=> await OnExprsShouldReload(true);
|
||||
|
||||
private ValueTask OnExprsShouldReload(bool _)
|
||||
=> new(ReloadInternal(_bot.GetCurrentGuildIds()));
|
||||
|
||||
private ValueTask OnGexprAdded(NadekoExpression c)
|
||||
{
|
||||
lock (_gexprWriteLock)
|
||||
{
|
||||
var newGlobalReactions = new NadekoExpression[globalExpressions.Length + 1];
|
||||
Array.Copy(globalExpressions, newGlobalReactions, globalExpressions.Length);
|
||||
newGlobalReactions[globalExpressions.Length] = c;
|
||||
globalExpressions = newGlobalReactions;
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
private ValueTask OnGexprEdited(NadekoExpression c)
|
||||
{
|
||||
lock (_gexprWriteLock)
|
||||
{
|
||||
for (var i = 0; i < globalExpressions.Length; i++)
|
||||
{
|
||||
if (globalExpressions[i].Id == c.Id)
|
||||
{
|
||||
globalExpressions[i] = c;
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
// if edited expr is not found?!
|
||||
// add it
|
||||
OnGexprAdded(c);
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
private ValueTask OnGexprDeleted(int id)
|
||||
{
|
||||
lock (_gexprWriteLock)
|
||||
{
|
||||
var newGlobalReactions = DeleteInternal(globalExpressions, id, out _);
|
||||
globalExpressions = newGlobalReactions;
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
public Task TriggerReloadExpressions()
|
||||
=> _pubSub.Pub(_exprsReloadedKey, true);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Client Event Handlers
|
||||
|
||||
private Task OnLeftGuild(SocketGuild arg)
|
||||
{
|
||||
newguildExpressions.TryRemove(arg.Id, out _);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async Task OnJoinedGuild(GuildConfig gc)
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
var exprs = await uow.Set<NadekoExpression>().AsNoTracking().Where(x => x.GuildId == gc.GuildId).ToArrayAsync();
|
||||
|
||||
newguildExpressions[gc.GuildId] = exprs;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Basic Operations
|
||||
|
||||
public async Task<NadekoExpression> AddAsync(ulong? guildId, string key, string message,
|
||||
bool ca = false, bool ad = false, bool dm = false)
|
||||
{
|
||||
key = key.ToLowerInvariant();
|
||||
var expr = new NadekoExpression
|
||||
{
|
||||
GuildId = guildId,
|
||||
Trigger = key,
|
||||
Response = message,
|
||||
ContainsAnywhere = ca,
|
||||
AutoDeleteTrigger = ad,
|
||||
DmResponse = dm
|
||||
};
|
||||
|
||||
if (expr.Response.Contains("%target%", StringComparison.OrdinalIgnoreCase))
|
||||
expr.AllowTarget = true;
|
||||
|
||||
await using (var uow = _db.GetDbContext())
|
||||
{
|
||||
uow.Set<NadekoExpression>().Add(expr);
|
||||
await uow.SaveChangesAsync();
|
||||
}
|
||||
|
||||
await AddInternalAsync(guildId, expr);
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
public async Task<NadekoExpression> EditAsync(ulong? guildId, int id, string message,
|
||||
bool? ca = null, bool? ad = null, bool? dm = null)
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
var expr = uow.Set<NadekoExpression>().GetById(id);
|
||||
|
||||
if (expr is null || expr.GuildId != guildId)
|
||||
return null;
|
||||
|
||||
// disable allowtarget if message had target, but it was removed from it
|
||||
if (!message.Contains("%target%", StringComparison.OrdinalIgnoreCase)
|
||||
&& expr.Response.Contains("%target%", StringComparison.OrdinalIgnoreCase))
|
||||
expr.AllowTarget = false;
|
||||
|
||||
expr.Response = message;
|
||||
|
||||
// enable allow target if message is edited to contain target
|
||||
if (expr.Response.Contains("%target%", StringComparison.OrdinalIgnoreCase))
|
||||
expr.AllowTarget = true;
|
||||
|
||||
expr.ContainsAnywhere = ca ?? expr.ContainsAnywhere;
|
||||
expr.AutoDeleteTrigger = ad ?? expr.AutoDeleteTrigger;
|
||||
expr.DmResponse = dm ?? expr.DmResponse;
|
||||
|
||||
await uow.SaveChangesAsync();
|
||||
await UpdateInternalAsync(guildId, expr);
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
|
||||
public async Task<NadekoExpression> DeleteAsync(ulong? guildId, int id)
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
var toDelete = uow.Set<NadekoExpression>().GetById(id);
|
||||
|
||||
if (toDelete is null)
|
||||
return null;
|
||||
|
||||
if ((toDelete.IsGlobal() && guildId is null) || guildId == toDelete.GuildId)
|
||||
{
|
||||
uow.Set<NadekoExpression>().Remove(toDelete);
|
||||
await uow.SaveChangesAsync();
|
||||
await DeleteInternalAsync(guildId, id);
|
||||
return toDelete;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public NadekoExpression[] GetExpressionsFor(ulong? maybeGuildId)
|
||||
{
|
||||
if (maybeGuildId is { } guildId)
|
||||
return newguildExpressions.TryGetValue(guildId, out var exprs) ? exprs : Array.Empty<NadekoExpression>();
|
||||
|
||||
return globalExpressions;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public async Task<bool> ToggleGlobalExpressionsAsync(ulong guildId)
|
||||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
var gc = ctx.GuildConfigsForId(guildId, set => set);
|
||||
var toReturn = gc.DisableGlobalExpressions = !gc.DisableGlobalExpressions;
|
||||
await ctx.SaveChangesAsync();
|
||||
|
||||
if (toReturn)
|
||||
_disabledGlobalExpressionGuilds.Add(guildId);
|
||||
else
|
||||
_disabledGlobalExpressionGuilds.TryRemove(guildId);
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
|
||||
public async Task<(IReadOnlyCollection<NadekoExpression> Exprs, int TotalCount)> FindExpressionsAsync(ulong guildId,
|
||||
string query, int page)
|
||||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
|
||||
if (newguildExpressions.TryGetValue(guildId, out var exprs))
|
||||
{
|
||||
return (exprs.Where(x => x.Trigger.Contains(query))
|
||||
.Skip(page * 9)
|
||||
.Take(9)
|
||||
.ToArray(), exprs.Length);
|
||||
}
|
||||
|
||||
return ([], 0);
|
||||
}
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Modules.NadekoExpressions;
|
||||
|
||||
namespace NadekoBot.Common.TypeReaders;
|
||||
|
||||
public sealed class CommandOrExprTypeReader : NadekoTypeReader<CommandOrExprInfo>
|
||||
{
|
||||
private readonly CommandService _cmds;
|
||||
private readonly ICommandHandler _commandHandler;
|
||||
private readonly NadekoExpressionsService _exprs;
|
||||
|
||||
public CommandOrExprTypeReader(CommandService cmds, NadekoExpressionsService exprs, ICommandHandler commandHandler)
|
||||
{
|
||||
_cmds = cmds;
|
||||
_exprs = exprs;
|
||||
_commandHandler = commandHandler;
|
||||
}
|
||||
|
||||
public override async ValueTask<TypeReaderResult<CommandOrExprInfo>> ReadAsync(ICommandContext ctx, string input)
|
||||
{
|
||||
if (_exprs.ExpressionExists(ctx.Guild?.Id, input))
|
||||
return TypeReaderResult.FromSuccess(new CommandOrExprInfo(input, CommandOrExprInfo.Type.Custom));
|
||||
|
||||
var cmd = await new CommandTypeReader(_commandHandler, _cmds).ReadAsync(ctx, input);
|
||||
if (cmd.IsSuccess)
|
||||
{
|
||||
return TypeReaderResult.FromSuccess(new CommandOrExprInfo(((CommandInfo)cmd.Values.First().Value).Name,
|
||||
CommandOrExprInfo.Type.Normal));
|
||||
}
|
||||
|
||||
return TypeReaderResult.FromError<CommandOrExprInfo>(CommandError.ParseFailed, "No such command or expression found.");
|
||||
}
|
||||
}
|
@@ -128,7 +128,7 @@ public partial class Gambling
|
||||
embed.AddField(full, cStr);
|
||||
}
|
||||
|
||||
msg = await ctx.Channel.EmbedAsync(embed);
|
||||
msg = await EmbedAsync(embed);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
@@ -1,39 +0,0 @@
|
||||
using Nadeko.Bot.Modules.Gambling.Gambling._Common;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling;
|
||||
|
||||
public partial class Gambling
|
||||
{
|
||||
[Group]
|
||||
public class CleanupCommands : CleanupModuleBase
|
||||
{
|
||||
private readonly IGamblingCleanupService _gcs;
|
||||
|
||||
public CleanupCommands(IGamblingCleanupService gcs)
|
||||
{
|
||||
_gcs = gcs;
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[OwnerOnly]
|
||||
public Task DeleteWaifus()
|
||||
=> ConfirmActionInternalAsync("Delete Waifus", () => _gcs.DeleteWaifus());
|
||||
|
||||
[Cmd]
|
||||
[OwnerOnly]
|
||||
public async Task DeleteWaifu(IUser user)
|
||||
=> await DeleteWaifu(user.Id);
|
||||
|
||||
[Cmd]
|
||||
[OwnerOnly]
|
||||
public Task DeleteWaifu(ulong userId)
|
||||
=> ConfirmActionInternalAsync($"Delete Waifu {userId}", () => _gcs.DeleteWaifu(userId));
|
||||
|
||||
|
||||
[Cmd]
|
||||
[OwnerOnly]
|
||||
public Task DeleteCurrency()
|
||||
=> ConfirmActionInternalAsync("Delete Currency", () => _gcs.DeleteCurrency());
|
||||
|
||||
}
|
||||
}
|
@@ -167,7 +167,7 @@ public partial class Gambling
|
||||
|
||||
|
||||
if (msg is null)
|
||||
msg = await ctx.Channel.EmbedAsync(embed);
|
||||
msg = await EmbedAsync(embed);
|
||||
else
|
||||
await msg.ModifyAsync(x => x.Embed = embed.Build());
|
||||
}
|
||||
|
@@ -1,5 +1,4 @@
|
||||
using NadekoBot.Common;
|
||||
using NadekoBot.Modules.Gambling.Services;
|
||||
using NadekoBot.Modules.Gambling.Services;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling;
|
||||
|
||||
|
@@ -148,7 +148,7 @@ public partial class Gambling
|
||||
.AddField(Format.Bold("Result"),
|
||||
string.Join(" ", rolls.Select(c => Format.Code($"[{c}]"))));
|
||||
|
||||
await ctx.Channel.EmbedAsync(embed);
|
||||
await EmbedAsync(embed);
|
||||
}
|
||||
else if ((match = _dndRegex.Match(arg)).Length != 0)
|
||||
{
|
||||
@@ -180,7 +180,7 @@ public partial class Gambling
|
||||
=> Format.Code(x.ToString()))))
|
||||
.AddField(Format.Bold("Sum"),
|
||||
sum + " + " + add + " - " + sub + " = " + (sum + add - sub));
|
||||
await ctx.Channel.EmbedAsync(embed);
|
||||
await EmbedAsync(embed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,7 @@
|
||||
using NadekoBot.Modules.Gambling.Common;
|
||||
using NadekoBot.Modules.Gambling.Common.Events;
|
||||
using NadekoBot.Modules.Gambling.Services;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling;
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Modules.Gambling.Common;
|
||||
using NadekoBot.Modules.Gambling.Common.Events;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling.Services;
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#nullable disable
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling.Common.Events;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#nullable disable
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling.Common.Events;
|
||||
|
||||
|
@@ -130,7 +130,7 @@ public partial class Gambling
|
||||
str = Format.Bold(GetText(strs.better_luck));
|
||||
}
|
||||
|
||||
await ctx.Channel.EmbedAsync(_eb.Create()
|
||||
await EmbedAsync(_eb.Create()
|
||||
.WithAuthor(ctx.User)
|
||||
.WithDescription(str)
|
||||
.WithOkColor()
|
||||
|
@@ -8,7 +8,6 @@ using NadekoBot.Modules.Gambling.Common;
|
||||
using NadekoBot.Modules.Gambling.Services;
|
||||
using NadekoBot.Modules.Utility.Services;
|
||||
using NadekoBot.Services.Currency;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using System.Collections.Immutable;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
@@ -103,7 +102,7 @@ public partial class Gambling : GamblingModule<GamblingService>
|
||||
|
||||
eb.WithDescription(str);
|
||||
|
||||
await ctx.Channel.EmbedAsync(eb);
|
||||
await EmbedAsync(eb);
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
@@ -131,7 +130,7 @@ public partial class Gambling : GamblingModule<GamblingService>
|
||||
.WithOkColor();
|
||||
|
||||
// ec.Cash already contains ec.Bot as it's the total of all values in the CurrencyAmount column of the DiscordUser table
|
||||
await ctx.Channel.EmbedAsync(embed);
|
||||
await EmbedAsync(embed);
|
||||
}
|
||||
|
||||
private static readonly FeatureLimitKey _timelyKey = new FeatureLimitKey()
|
||||
@@ -332,7 +331,7 @@ public partial class Gambling : GamblingModule<GamblingService>
|
||||
|
||||
embed.WithDescription(sb.ToString());
|
||||
embed.WithFooter(GetText(strs.page(page + 1)));
|
||||
await ctx.Channel.EmbedAsync(embed);
|
||||
await EmbedAsync(embed);
|
||||
}
|
||||
|
||||
private static string GetFormattedCurtrDate(CurrencyTransaction ct)
|
||||
@@ -375,7 +374,7 @@ public partial class Gambling : GamblingModule<GamblingService>
|
||||
|
||||
eb.WithFooter(GetFormattedCurtrDate(tr));
|
||||
|
||||
await ctx.Channel.EmbedAsync(eb);
|
||||
await EmbedAsync(eb);
|
||||
}
|
||||
|
||||
private string GetHumanReadableTransaction(string type, string subType, ulong? maybeUserId)
|
||||
|
@@ -6,7 +6,6 @@ using NadekoBot.Db;
|
||||
using NadekoBot.Db.Models;
|
||||
using NadekoBot.Modules.Gambling.Common;
|
||||
using NadekoBot.Modules.Gambling.Common.Connect4;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling.Services;
|
||||
|
||||
|
@@ -1,7 +1,6 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Modules.Gambling.Services;
|
||||
using System.Numerics;
|
||||
using NadekoBot.Common;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling.Common;
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Db;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
using SixLabors.Fonts;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.Drawing.Processing;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#nullable disable
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling.Services;
|
||||
|
||||
|
@@ -3,7 +3,7 @@ using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Db;
|
||||
using NadekoBot.Modules.Gambling.Common;
|
||||
using NadekoBot.Modules.Gambling.Services;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
using NadekoBot.Modules.Administration;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling;
|
||||
@@ -246,7 +246,7 @@ public partial class Gambling
|
||||
.WithTitle("Executing shop command")
|
||||
.WithDescription(cmd);
|
||||
|
||||
var msgTask = ctx.Channel.EmbedAsync(eb);
|
||||
var msgTask = EmbedAsync(eb);
|
||||
|
||||
await _cs.AddAsync(entry.AuthorId,
|
||||
GetProfitAmount(entry.Price),
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#nullable disable
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Db;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling.Services;
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
using NadekoBot.Modules.Gambling.Common;
|
||||
using NadekoBot.Modules.Gambling.Common.Waifu;
|
||||
using NadekoBot.Modules.Gambling.Services;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling;
|
||||
|
||||
@@ -217,7 +217,7 @@ public partial class Gambling
|
||||
embed.AddField("#" + ((page * 9) + j + 1) + " - " + N(w.Price), GetLbString(w));
|
||||
}
|
||||
|
||||
await ctx.Channel.EmbedAsync(embed);
|
||||
await EmbedAsync(embed);
|
||||
}
|
||||
|
||||
private string GetLbString(WaifuLbResult w)
|
||||
|
@@ -7,7 +7,6 @@ using NadekoBot.Db;
|
||||
using NadekoBot.Db.Models;
|
||||
using NadekoBot.Modules.Gambling.Common;
|
||||
using NadekoBot.Modules.Gambling.Common.Waifu;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Gambling.Services;
|
||||
|
||||
|
@@ -1,7 +1,5 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace Nadeko.Bot.Db.Models;
|
||||
namespace NadekoBot.Db.Models;
|
||||
|
||||
public class WaifuInfo : DbEntity
|
||||
{
|
||||
|
@@ -4,8 +4,6 @@ using LinqToDB.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
using Nadeko.Bot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Db;
|
||||
|
||||
public static class WaifuExtensions
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#nullable disable
|
||||
namespace Nadeko.Bot.Db.Models;
|
||||
namespace NadekoBot.Db.Models;
|
||||
|
||||
public class WaifuItem : DbEntity
|
||||
{
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#nullable disable
|
||||
namespace Nadeko.Bot.Db.Models;
|
||||
namespace NadekoBot.Db.Models;
|
||||
|
||||
public class WaifuLbResult
|
||||
{
|
||||
|
@@ -1,7 +1,5 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace Nadeko.Bot.Db.Models;
|
||||
namespace NadekoBot.Db.Models;
|
||||
|
||||
public class WaifuUpdate : DbEntity
|
||||
{
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#nullable disable
|
||||
namespace Nadeko.Bot.Db.Models;
|
||||
namespace NadekoBot.Db.Models;
|
||||
|
||||
public enum WaifuUpdateType
|
||||
{
|
||||
|
@@ -1,8 +1,8 @@
|
||||
using LinqToDB;
|
||||
using LinqToDB.EntityFrameworkCore;
|
||||
using NadekoBot.Db.Models;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
|
||||
namespace Nadeko.Bot.Modules.Gambling.Gambling._Common;
|
||||
namespace NadekoBot.Modules.Gambling;
|
||||
|
||||
public class GamblingCleanupService : IGamblingCleanupService, INService
|
||||
{
|
||||
@@ -16,45 +16,41 @@ public class GamblingCleanupService : IGamblingCleanupService, INService
|
||||
public async Task DeleteWaifus()
|
||||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
await ctx.Set<WaifuInfo>().DeleteAsync();
|
||||
await ctx.Set<WaifuItem>().DeleteAsync();
|
||||
await ctx.Set<WaifuUpdate>().DeleteAsync();
|
||||
await ctx.SaveChangesAsync();
|
||||
await ctx.GetTable<WaifuInfo>().DeleteAsync();
|
||||
await ctx.GetTable<WaifuItem>().DeleteAsync();
|
||||
await ctx.GetTable<WaifuUpdate>().DeleteAsync();
|
||||
}
|
||||
|
||||
public async Task DeleteWaifu(ulong userId)
|
||||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
await ctx.Set<WaifuUpdate>()
|
||||
await ctx.GetTable<WaifuUpdate>()
|
||||
.Where(x => x.User.UserId == userId)
|
||||
.DeleteAsync();
|
||||
await ctx.Set<WaifuItem>()
|
||||
await ctx.GetTable<WaifuItem>()
|
||||
.Where(x => x.WaifuInfo.Waifu.UserId == userId)
|
||||
.DeleteAsync();
|
||||
await ctx.Set<WaifuInfo>()
|
||||
await ctx.GetTable<WaifuInfo>()
|
||||
.Where(x => x.Claimer.UserId == userId)
|
||||
.UpdateAsync(old => new WaifuInfo()
|
||||
{
|
||||
ClaimerId = null,
|
||||
});
|
||||
await ctx.Set<WaifuInfo>()
|
||||
await ctx.GetTable<WaifuInfo>()
|
||||
.Where(x => x.Waifu.UserId == userId)
|
||||
.DeleteAsync();
|
||||
await ctx.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task DeleteCurrency()
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
await uow.Set<DiscordUser>().UpdateAsync(_ => new DiscordUser()
|
||||
await using var ctx = _db.GetDbContext();
|
||||
await ctx.GetTable<DiscordUser>().UpdateAsync(_ => new DiscordUser()
|
||||
{
|
||||
CurrencyAmount = 0
|
||||
});
|
||||
|
||||
await uow.Set<CurrencyTransaction>().DeleteAsync();
|
||||
await uow.Set<PlantedCurrency>().DeleteAsync();
|
||||
await uow.Set<BankUser>().DeleteAsync();
|
||||
await uow.SaveChangesAsync();
|
||||
await ctx.GetTable<CurrencyTransaction>().DeleteAsync();
|
||||
await ctx.GetTable<PlantedCurrency>().DeleteAsync();
|
||||
await ctx.GetTable<BankUser>().DeleteAsync();
|
||||
}
|
||||
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
namespace Nadeko.Bot.Modules.Gambling.Gambling._Common;
|
||||
namespace NadekoBot.Modules.Gambling;
|
||||
|
||||
public interface IGamblingCleanupService
|
||||
{
|
||||
|
@@ -74,7 +74,7 @@ public partial class Games
|
||||
GetText(strs.acro_started(Format.Bold(string.Join(".", game.StartingLetters)))))
|
||||
.WithFooter(GetText(strs.acro_started_footer(game.Opts.SubmissionTime)));
|
||||
|
||||
return ctx.Channel.EmbedAsync(embed);
|
||||
return EmbedAsync(embed);
|
||||
}
|
||||
|
||||
private Task Game_OnUserVoted(string user)
|
||||
@@ -92,7 +92,7 @@ public partial class Games
|
||||
|
||||
if (submissions.Length == 1)
|
||||
{
|
||||
await ctx.Channel.EmbedAsync(_eb.Create()
|
||||
await EmbedAsync(_eb.Create()
|
||||
.WithOkColor()
|
||||
.WithDescription(GetText(
|
||||
strs.acro_winner_only(
|
||||
@@ -114,7 +114,7 @@ public partial class Games
|
||||
--")))
|
||||
.WithFooter(GetText(strs.acro_vote));
|
||||
|
||||
await ctx.Channel.EmbedAsync(embed);
|
||||
await EmbedAsync(embed);
|
||||
}
|
||||
|
||||
private async Task Game_OnEnded(AcrophobiaGame game, ImmutableArray<KeyValuePair<AcrophobiaUser, int>> votes)
|
||||
@@ -134,7 +134,7 @@ public partial class Games
|
||||
Format.Bold(winner.Value.ToString()))))
|
||||
.WithFooter(winner.Key.Input);
|
||||
|
||||
await ctx.Channel.EmbedAsync(embed);
|
||||
await EmbedAsync(embed);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,5 +1,4 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Common;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Db.Models;
|
||||
using NadekoBot.Modules.Games.Common;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Db;
|
||||
using NadekoBot.Modules.Games.Services;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Games;
|
||||
|
||||
|
@@ -1,5 +1,4 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Modules.Games.Common;
|
||||
using NadekoBot.Modules.Games.Services;
|
||||
|
||||
namespace NadekoBot.Modules.Games;
|
||||
@@ -39,7 +38,7 @@ public partial class Games : NadekoModule<GamesService>
|
||||
return;
|
||||
|
||||
var res = _service.GetEightballResponse(ctx.User.Id, question);
|
||||
await ctx.Channel.EmbedAsync(_eb.Create()
|
||||
await EmbedAsync(_eb.Create()
|
||||
.WithOkColor()
|
||||
.WithDescription(ctx.User.ToString())
|
||||
.AddField("❓ " + GetText(strs.question), question)
|
||||
|
@@ -62,7 +62,7 @@ public partial class Games
|
||||
|
||||
var eb = GetEmbed(_eb, hangman);
|
||||
eb.WithDescription(GetText(strs.hangman_game_started));
|
||||
await ctx.Channel.EmbedAsync(eb);
|
||||
await EmbedAsync(eb);
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
|
@@ -97,7 +97,7 @@ public partial class Games
|
||||
.WithDescription(removed.Text.TrimTo(50))
|
||||
.WithOkColor();
|
||||
|
||||
await ctx.Channel.EmbedAsync(embed);
|
||||
await EmbedAsync(embed);
|
||||
}
|
||||
}
|
||||
}
|
@@ -171,7 +171,7 @@ public partial class Games
|
||||
if (Uri.IsWellFormedUriString(question.ImageUrl, UriKind.Absolute))
|
||||
questionEmbed.WithImageUrl(question.ImageUrl);
|
||||
|
||||
questionMessage = await ctx.Channel.EmbedAsync(questionEmbed);
|
||||
questionMessage = await EmbedAsync(questionEmbed);
|
||||
}
|
||||
catch (HttpException ex) when (ex.HttpCode is HttpStatusCode.NotFound or HttpStatusCode.Forbidden
|
||||
or HttpStatusCode.BadRequest)
|
||||
@@ -194,7 +194,7 @@ public partial class Games
|
||||
if (Uri.IsWellFormedUriString(question.AnswerImageUrl, UriKind.Absolute))
|
||||
embed.WithImageUrl(question.AnswerImageUrl);
|
||||
|
||||
await ctx.Channel.EmbedAsync(embed);
|
||||
await EmbedAsync(embed);
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -218,7 +218,7 @@ public partial class Games
|
||||
{
|
||||
try
|
||||
{
|
||||
await ctx.Channel.EmbedAsync(_eb.Create(ctx)
|
||||
await EmbedAsync(_eb.Create(ctx)
|
||||
.WithOkColor()
|
||||
.WithAuthor(GetText(strs.trivia_ended))
|
||||
.WithTitle(GetText(strs.leaderboard))
|
||||
@@ -252,7 +252,7 @@ public partial class Games
|
||||
|
||||
if (isWin)
|
||||
{
|
||||
await ctx.Channel.EmbedAsync(embed);
|
||||
await EmbedAsync(embed);
|
||||
|
||||
var reward = _gamesConfig.Data.Trivia.CurrencyReward;
|
||||
if (reward > 0)
|
||||
@@ -264,7 +264,7 @@ public partial class Games
|
||||
embed.WithDescription(GetText(strs.trivia_guess(user.Name,
|
||||
Format.Bold(question.Answer))));
|
||||
|
||||
await ctx.Channel.EmbedAsync(embed);
|
||||
await EmbedAsync(embed);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
@@ -5,7 +5,6 @@ using NadekoBot.Modules.Help.Services;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using NadekoBot.Common;
|
||||
using Nadeko.Common.Medusa;
|
||||
using JsonSerializer = System.Text.Json.JsonSerializer;
|
||||
|
||||
@@ -294,7 +293,7 @@ public sealed class Help : NadekoModule<HelpService>
|
||||
}
|
||||
|
||||
embed.WithFooter(GetText(strs.commands_instr(prefix)));
|
||||
await ctx.Channel.EmbedAsync(embed);
|
||||
await EmbedAsync(embed);
|
||||
}
|
||||
|
||||
private async Task Group(ModuleInfo group)
|
||||
@@ -308,7 +307,7 @@ public sealed class Help : NadekoModule<HelpService>
|
||||
eb.AddField(prefix + cmd.Aliases.First(), cmd.RealSummary(_strings, _medusae, Culture, prefix));
|
||||
}
|
||||
|
||||
await ctx.Channel.EmbedAsync(eb);
|
||||
await EmbedAsync(eb);
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
|
@@ -1,4 +1,3 @@
|
||||
using NadekoBot.Common;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
|
||||
namespace NadekoBot.Modules.Help.Services;
|
||||
|
@@ -77,7 +77,7 @@ public partial class Medusa : NadekoModule<IMedusaLoaderService>
|
||||
return;
|
||||
}
|
||||
|
||||
await ctx.Channel.EmbedAsync(_eb.Create(ctx)
|
||||
await EmbedAsync(_eb.Create(ctx)
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.loaded_medusae))
|
||||
.WithDescription(loaded.Select(x => x.Name)
|
||||
@@ -177,7 +177,7 @@ public partial class Medusa : NadekoModule<IMedusaLoaderService>
|
||||
: cmdNames,
|
||||
true);
|
||||
|
||||
await ctx.Channel.EmbedAsync(eb);
|
||||
await EmbedAsync(eb);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -224,6 +224,6 @@ public partial class Medusa : NadekoModule<IMedusaLoaderService>
|
||||
""", true);
|
||||
}
|
||||
|
||||
await ctx.Channel.EmbedAsync(eb);
|
||||
await EmbedAsync(eb);
|
||||
}
|
||||
}
|
@@ -1,24 +0,0 @@
|
||||
using LinqToDB;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Music;
|
||||
|
||||
public sealed partial class Music
|
||||
{
|
||||
public class CleanupCommands : NadekoModule
|
||||
{
|
||||
private readonly DbService _db;
|
||||
|
||||
public CleanupCommands(DbService db)
|
||||
{
|
||||
_db = db;
|
||||
}
|
||||
|
||||
public async Task DeletePlaylists()
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
await uow.Set<MusicPlaylist>().DeleteAsync();
|
||||
await uow.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Modules.Music.Services;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Music;
|
||||
|
||||
@@ -586,7 +586,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
|
||||
if (Uri.IsWellFormedUriString(track.Url, UriKind.Absolute))
|
||||
embed.WithUrl(track.Url);
|
||||
|
||||
await ctx.Channel.EmbedAsync(embed);
|
||||
await EmbedAsync(embed);
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
|
@@ -1,7 +1,8 @@
|
||||
#nullable disable
|
||||
using LinqToDB;
|
||||
using NadekoBot.Db;
|
||||
using NadekoBot.Modules.Music.Services;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Music;
|
||||
|
||||
@@ -55,7 +56,7 @@ public sealed partial class Music
|
||||
playlists.Select(r => GetText(strs.playlists(r.Id, r.Name, r.Author, r.Songs.Count)))))
|
||||
.WithOkColor();
|
||||
|
||||
await ctx.Channel.EmbedAsync(embed);
|
||||
await EmbedAsync(embed);
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
@@ -150,11 +151,11 @@ public sealed partial class Music
|
||||
await uow.SaveChangesAsync();
|
||||
}
|
||||
|
||||
await ctx.Channel.EmbedAsync(_eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.playlist_saved))
|
||||
.AddField(GetText(strs.name), name)
|
||||
.AddField(GetText(strs.id), playlist.Id.ToString()));
|
||||
await EmbedAsync(_eb.Create()
|
||||
.WithOkColor()
|
||||
.WithTitle(GetText(strs.playlist_saved))
|
||||
.AddField(GetText(strs.name), name)
|
||||
.AddField(GetText(strs.id), playlist.Id.ToString()));
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
@@ -225,5 +226,14 @@ public sealed partial class Music
|
||||
_playlistLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[OwnerOnly]
|
||||
public async Task DeletePlaylists()
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
await uow.Set<MusicPlaylist>().DeleteAsync();
|
||||
await uow.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace NadekoBot.Modules.Music.Services;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
using NadekoBot.Db;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace NadekoBot.Modules.Music.Services;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Music;
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
using Ayu.Discord.Voice;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
@@ -1,6 +1,4 @@
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||
|
||||
namespace NadekoBot.Modules.Music;
|
||||
namespace NadekoBot.Modules.Music;
|
||||
|
||||
public sealed partial class MusicQueue
|
||||
{
|
||||
|
@@ -1,6 +1,6 @@
|
||||
#nullable disable
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Db;
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#nullable disable
|
||||
namespace Nadeko.Bot.Db.Models;
|
||||
namespace NadekoBot.Db.Models;
|
||||
|
||||
public class MusicPlaylist : DbEntity
|
||||
{
|
||||
|
@@ -1,6 +1,6 @@
|
||||
#nullable disable
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Db;
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#nullable disable
|
||||
namespace Nadeko.Bot.Db.Models;
|
||||
namespace NadekoBot.Db.Models;
|
||||
|
||||
public class MusicPlayerSettings
|
||||
{
|
||||
|
@@ -4,7 +4,7 @@ using LinqToDB.EntityFrameworkCore;
|
||||
using NadekoBot.Modules.Gambling.Services;
|
||||
using NadekoBot.Modules.Patronage;
|
||||
using NadekoBot.Services.Currency;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Utility;
|
||||
|
||||
|
@@ -49,7 +49,7 @@ public partial class Patronage : NadekoModule
|
||||
//
|
||||
// var eb = _eb.Create(ctx);
|
||||
//
|
||||
// await ctx.Channel.EmbedAsync(eb.WithDescription($"Added **{days}** days of Patron benefits to {user.Mention}!")
|
||||
// await EmbedAsync(eb.WithDescription($"Added **{days}** days of Patron benefits to {user.Mention}!")
|
||||
// .AddField("Tier", Format.Bold(patron.Tier.ToString()), true)
|
||||
// .AddField("Amount", $"**{patron.Amount / 100.0f:N1}$**", true)
|
||||
// .AddField("Until", TimestampTag.FromDateTime(patron.ValidThru.AddDays(1))));
|
||||
|
@@ -322,7 +322,7 @@ public sealed class PatronageService
|
||||
_ = ctx.WarningAsync();
|
||||
|
||||
if (ctx.Guild?.OwnerId == ctx.User.Id)
|
||||
_ = ctx.Channel.EmbedAsync(eb);
|
||||
_ = ctx.Channel.EmbedAsync(eb, replyTo: ctx.Message);
|
||||
else
|
||||
_ = ctx.User.EmbedAsync(eb);
|
||||
|
||||
@@ -356,7 +356,7 @@ public sealed class PatronageService
|
||||
|
||||
// send the message in the server in case it's the owner
|
||||
if (ctx.Guild?.OwnerId == ctx.User.Id)
|
||||
_ = ctx.Channel.EmbedAsync(eb);
|
||||
_ = ctx.Channel.EmbedAsync(eb, replyTo: ctx.Message);
|
||||
else
|
||||
_ = ctx.User.EmbedAsync(eb);
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
#nullable disable
|
||||
using NadekoBot.Modules.Permissions.Services;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Permissions;
|
||||
|
||||
|
@@ -4,7 +4,7 @@ using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Common.TypeReaders;
|
||||
using NadekoBot.Db;
|
||||
using NadekoBot.Modules.Permissions.Services;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Permissions;
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Db;
|
||||
using NadekoBot.Modules.Permissions.Services;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Permissions;
|
||||
|
||||
@@ -63,7 +63,7 @@ public partial class Permissions
|
||||
embed.AddField($"{GetEnabledEmoji(config.FilterInvitesEnabled)} Filter Invites",
|
||||
await GetChannelListAsync(config.FilterInvitesChannels));
|
||||
|
||||
await ctx.Channel.EmbedAsync(embed);
|
||||
await EmbedAsync(embed);
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
|
@@ -2,7 +2,7 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Db;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Permissions.Services;
|
||||
|
||||
|
@@ -38,7 +38,7 @@ public partial class Permissions
|
||||
if (blockedCommands.Any())
|
||||
embed.AddField(GetText(strs.blocked_commands), string.Join("\n", _service.BlockedCommands));
|
||||
|
||||
await ctx.Channel.EmbedAsync(embed);
|
||||
await EmbedAsync(embed);
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#nullable disable
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Permissions.Common;
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#nullable disable
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Permissions.Common;
|
||||
|
||||
|
@@ -4,7 +4,7 @@ using NadekoBot.Common.TypeReaders.Models;
|
||||
using NadekoBot.Db;
|
||||
using NadekoBot.Modules.Permissions.Common;
|
||||
using NadekoBot.Modules.Permissions.Services;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Permissions;
|
||||
|
||||
@@ -115,7 +115,7 @@ public partial class Permissions : NadekoModule<PermissionService>
|
||||
return str;
|
||||
}));
|
||||
|
||||
await ctx.Channel.SendMessageAsync(toSend);
|
||||
await SendConfirmAsync(toSend);
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
|
@@ -3,7 +3,7 @@ using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Common.ModuleBehaviors;
|
||||
using NadekoBot.Db;
|
||||
using NadekoBot.Modules.Permissions.Common;
|
||||
using Nadeko.Bot.Db.Models;
|
||||
using NadekoBot.Db.Models;
|
||||
|
||||
namespace NadekoBot.Modules.Permissions.Services;
|
||||
|
||||
|
@@ -35,7 +35,7 @@ public partial class Searches
|
||||
// .AddField(GetText(strs.genres), string.Join(" ", novelData.Genres.Any() ? novelData.Genres : new[] { "none" }), true)
|
||||
// .WithFooter($"{GetText(strs.score)} {novelData.Score}");
|
||||
//
|
||||
// await ctx.Channel.EmbedAsync(embed);
|
||||
// await EmbedAsync(embed);
|
||||
// }
|
||||
|
||||
[Cmd]
|
||||
@@ -110,7 +110,7 @@ public partial class Searches
|
||||
.WithUrl(fullQueryLink)
|
||||
.WithImageUrl(imageUrl);
|
||||
|
||||
await ctx.Channel.EmbedAsync(embed);
|
||||
await EmbedAsync(embed);
|
||||
}
|
||||
|
||||
private static string MalInfoToEmoji(string info)
|
||||
@@ -165,7 +165,7 @@ public partial class Searches
|
||||
string.Join(",\n", animeData.Genres.Any() ? animeData.Genres : new[] { "none" }),
|
||||
true)
|
||||
.WithFooter($"{GetText(strs.score)} {animeData.AverageScore} / 100");
|
||||
await ctx.Channel.EmbedAsync(embed);
|
||||
await EmbedAsync(embed);
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
@@ -198,7 +198,7 @@ public partial class Searches
|
||||
true)
|
||||
.WithFooter($"{GetText(strs.score)} {mangaData.AverageScore} / 100");
|
||||
|
||||
await ctx.Channel.EmbedAsync(embed);
|
||||
await EmbedAsync(embed);
|
||||
}
|
||||
}
|
||||
}
|
@@ -92,7 +92,7 @@ public partial class Searches
|
||||
// .AddField("Change 200d", $"{sign200}{change200}", true)
|
||||
.WithFooter(stock.Exchange);
|
||||
|
||||
var message = await ctx.Channel.EmbedAsync(eb);
|
||||
var message = await EmbedAsync(eb);
|
||||
await using var imageData = await stockImageTask;
|
||||
if (imageData is null)
|
||||
return;
|
||||
|
@@ -117,7 +117,7 @@ public partial class Searches
|
||||
|
||||
if (!feeds.Any())
|
||||
{
|
||||
await ctx.Channel.EmbedAsync(_eb.Create().WithOkColor().WithDescription(GetText(strs.feed_no_feed)));
|
||||
await EmbedAsync(_eb.Create().WithOkColor().WithDescription(GetText(strs.feed_no_feed)));
|
||||
return;
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user