part 3 of the response rework

This commit is contained in:
Kwoth
2024-04-29 21:03:40 +00:00
parent d28c7b500d
commit daa2177559
65 changed files with 508 additions and 625 deletions

View File

@@ -52,6 +52,7 @@ Experimental changelog. Mostly based on [keepachangelog](https://keepachangelog.
- `.poll` commands removed, discord added polls. - `.poll` commands removed, discord added polls.
- `.scpl` and other music soundcloud commands have been removed as soundcloud isn't issuing new api tokens for years now - `.scpl` and other music soundcloud commands have been removed as soundcloud isn't issuing new api tokens for years now
- Removed a lot of useless and nsfw commands - Removed a lot of useless and nsfw commands
- Removed log voice presence TTS
## [4.3.22] - 23.04.2023 ## [4.3.22] - 23.04.2023

View File

@@ -40,13 +40,4 @@ public abstract class AnyContext
/// <param name="args">Arguments (if any) to format in</param> /// <param name="args">Arguments (if any) to format in</param>
/// <returns>A formatted localized string</returns> /// <returns>A formatted localized string</returns>
public abstract string GetText(string key, object[]? args = null); public abstract string GetText(string key, object[]? args = null);
/// <summary>
/// Creates a context-aware <see cref="IEmbedBuilder"/> instance
/// (future feature for guild-based embed colors)
/// Any code dealing with embeds should use it for future-proofness
/// instead of manually creating embedbuilder instances
/// </summary>
/// <returns>A context-aware <see cref="IEmbedBuilder"/> instance </returns>
public abstract EmbedBuilder Embed();
} }

View File

@@ -14,13 +14,13 @@
// //
// // unlocalized // // unlocalized
// public static Task<IUserMessage> SendConfirmAsync(this IMessageChannel ch, AnyContext ctx, string msg) // public static Task<IUserMessage> SendConfirmAsync(this IMessageChannel ch, AnyContext ctx, string msg)
// => ch.EmbedAsync(ctx.Embed().WithOkColor().WithDescription(msg)); // => _sender.Response(ch).Embed(ctx.Embed().WithOkColor().WithDescription(msg)).SendAsync();
// //
// public static Task<IUserMessage> SendPendingAsync(this IMessageChannel ch, AnyContext ctx, string msg) // public static Task<IUserMessage> SendPendingAsync(this IMessageChannel ch, AnyContext ctx, string msg)
// => ch.EmbedAsync(ctx.Embed().WithPendingColor().WithDescription(msg)); // => _sender.Response(ch).Embed(ctx.Embed().WithPendingColor().WithDescription(msg)).SendAsync();
// //
// public static Task<IUserMessage> SendErrorAsync(this IMessageChannel ch, AnyContext ctx, string msg) // public static Task<IUserMessage> SendErrorAsync(this IMessageChannel ch, AnyContext ctx, string msg)
// => ch.EmbedAsync(ctx.Embed().WithErrorColor().WithDescription(msg)); // => _sender.Response(ch).Embed(ctx.Embed().WithErrorColor().WithDescription(msg)).SendAsync();
// //
// // unlocalized // // unlocalized
// public static Task<IUserMessage> SendConfirmAsync(this AnyContext ctx, string msg) // public static Task<IUserMessage> SendConfirmAsync(this AnyContext ctx, string msg)

View File

@@ -1,18 +0,0 @@
using Discord;
namespace NadekoBot;
public interface IEmbedBuilder
{
EmbedBuilder WithDescription(string? desc);
EmbedBuilder WithTitle(string? title);
EmbedBuilder AddField(string title, object value, bool isInline = false);
EmbedBuilder WithFooter(string text, string? iconUrl = null);
EmbedBuilder WithAuthor(string name, string? iconUrl = null, string? url = null);
EmbedBuilder WithColor(EmbedColor color);
EmbedBuilder WithDiscordColor(Color color);
Embed Build();
EmbedBuilder WithUrl(string url);
EmbedBuilder WithImageUrl(string url);
EmbedBuilder WithThumbnailUrl(string url);
}

View File

@@ -32,6 +32,7 @@ public class LogSetting : DbEntity
//voicepresence //voicepresence
public ulong? LogVoicePresenceId { get; set; } public ulong? LogVoicePresenceId { get; set; }
public ulong? LogVoicePresenceTTSId { get; set; } public ulong? LogVoicePresenceTTSId { get; set; }
public ulong? LogWarnsId { get; set; } public ulong? LogWarnsId { get; set; }
} }

View File

@@ -19,18 +19,21 @@ public class GreetService : INService, IReadyExecutor
private readonly GreetGrouper<IUser> _byes = new(); private readonly GreetGrouper<IUser> _byes = new();
private readonly BotConfigService _bss; private readonly BotConfigService _bss;
private readonly IReplacementService _repSvc; private readonly IReplacementService _repSvc;
private readonly IMessageSenderService _sender;
public GreetService( public GreetService(
DiscordSocketClient client, DiscordSocketClient client,
IBot bot, IBot bot,
DbService db, DbService db,
BotConfigService bss, BotConfigService bss,
IMessageSenderService sender,
IReplacementService repSvc) IReplacementService repSvc)
{ {
_db = db; _db = db;
_client = client; _client = client;
_bss = bss; _bss = bss;
_repSvc = repSvc; _repSvc = repSvc;
_sender = sender;
_guildConfigsCache = new(bot.AllGuildConfigs.ToDictionary(g => g.GuildId, GreetSettings.Create)); _guildConfigsCache = new(bot.AllGuildConfigs.ToDictionary(g => g.GuildId, GreetSettings.Create));
@@ -281,6 +284,7 @@ public class GreetService : INService, IReadyExecutor
FullMode = BoundedChannelFullMode.DropNewest FullMode = BoundedChannelFullMode.DropNewest
}); });
private async Task<bool> GreetDmUser(GreetSettings conf, IGuildUser user) private async Task<bool> GreetDmUser(GreetSettings conf, IGuildUser user)
{ {
var completionSource = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously); var completionSource = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
@@ -298,32 +302,32 @@ public class GreetService : INService, IReadyExecutor
// .Build(); // .Build();
var repCtx = new ReplacementContext(client: _client, guild: user.Guild, users: user); var repCtx = new ReplacementContext(client: _client, guild: user.Guild, users: user);
var text = SmartText.CreateFrom(conf.DmGreetMessageText); var smartText = SmartText.CreateFrom(conf.DmGreetMessageText);
text = await _repSvc.ReplaceAsync(text, repCtx); smartText = await _repSvc.ReplaceAsync(smartText, repCtx);
if (text is SmartPlainText pt) if (smartText is SmartPlainText pt)
{ {
text = new SmartEmbedText() smartText = new SmartEmbedText()
{ {
Description = pt.Text Description = pt.Text
}; };
} }
if (text is SmartEmbedText set) if (smartText is SmartEmbedText set)
{ {
text = set with smartText = set with
{ {
Footer = CreateFooterSource(user) Footer = CreateFooterSource(user)
}; };
} }
else if (text is SmartEmbedTextArray seta) else if (smartText is SmartEmbedTextArray seta)
{ {
// if the greet dm message is a text array // if the greet dm message is a text array
var ebElem = seta.Embeds.LastOrDefault(); var ebElem = seta.Embeds.LastOrDefault();
if (ebElem is null) if (ebElem is null)
{ {
// if there are no embeds, add an embed with the footer // if there are no embeds, add an embed with the footer
text = seta with smartText = seta with
{ {
Embeds = new[] Embeds = new[]
{ {
@@ -355,7 +359,7 @@ public class GreetService : INService, IReadyExecutor
} }
} }
await user.SendAsync(text); await _sender.Response(user).Text(smartText).SendAsync();
} }
catch catch
{ {

View File

@@ -31,13 +31,13 @@ public class MuteService : INService
private readonly DiscordSocketClient _client; private readonly DiscordSocketClient _client;
private readonly DbService _db; private readonly DbService _db;
private readonly IEmbedBuilderService _eb; private readonly IMessageSenderService _sender;
public MuteService(DiscordSocketClient client, DbService db, IEmbedBuilderService eb) public MuteService(DiscordSocketClient client, DbService db, IMessageSenderService sender)
{ {
_client = client; _client = client;
_db = db; _db = db;
_eb = eb; _sender = sender;
using (var uow = db.GetDbContext()) using (var uow = db.GetDbContext())
{ {
@@ -122,13 +122,13 @@ public class MuteService : INService
if (string.IsNullOrWhiteSpace(reason)) if (string.IsNullOrWhiteSpace(reason))
return; return;
_ = Task.Run(() => user.SendMessageAsync(embed: new EmbedBuilder() _ = Task.Run(() => _sender.Response(user)
.WithDescription( .Embed(new EmbedBuilder()
$"You've been muted in {user.Guild} server") .WithDescription($"You've been muted in {user.Guild} server")
.AddField("Mute Type", type.ToString()) .AddField("Mute Type", type.ToString())
.AddField("Moderator", mod.ToString()) .AddField("Moderator", mod.ToString())
.AddField("Reason", reason) .AddField("Reason", reason))
.Build())); .SendAsync());
} }
private void OnUserUnmuted( private void OnUserUnmuted(
@@ -140,13 +140,13 @@ public class MuteService : INService
if (string.IsNullOrWhiteSpace(reason)) if (string.IsNullOrWhiteSpace(reason))
return; return;
_ = Task.Run(() => user.SendMessageAsync(embed: new EmbedBuilder() _ = Task.Run(() => _sender.Response(user)
.WithDescription( .Embed(new EmbedBuilder()
$"You've been unmuted in {user.Guild} server") .WithDescription($"You've been unmuted in {user.Guild} server")
.AddField("Unmute Type", type.ToString()) .AddField("Unmute Type", type.ToString())
.AddField("Moderator", mod.ToString()) .AddField("Moderator", mod.ToString())
.AddField("Reason", reason) .AddField("Reason", reason))
.Build())); .SendAsync());
} }
private Task Client_UserJoined(IGuildUser usr) private Task Client_UserJoined(IGuildUser usr)

View File

@@ -10,16 +10,16 @@ public sealed class CheckForUpdatesService : INService, IReadyExecutor
private readonly IBotCredsProvider _bcp; private readonly IBotCredsProvider _bcp;
private readonly IHttpClientFactory _httpFactory; private readonly IHttpClientFactory _httpFactory;
private readonly DiscordSocketClient _client; private readonly DiscordSocketClient _client;
private readonly IEmbedBuilderService _ebs; private readonly IMessageSenderService _sender;
public CheckForUpdatesService(BotConfigService bcs, IBotCredsProvider bcp, IHttpClientFactory httpFactory, public CheckForUpdatesService(BotConfigService bcs, IBotCredsProvider bcp, IHttpClientFactory httpFactory,
DiscordSocketClient client, IEmbedBuilderService ebs) DiscordSocketClient client, IMessageSenderService sender)
{ {
_bcs = bcs; _bcs = bcs;
_bcp = bcp; _bcp = bcp;
_httpFactory = httpFactory; _httpFactory = httpFactory;
_client = client; _client = client;
_ebs = ebs; _sender = sender;
} }
public async Task OnReadyAsync() public async Task OnReadyAsync()
@@ -86,7 +86,7 @@ public sealed class CheckForUpdatesService : INService, IReadyExecutor
.WithDescription(thisVersionChangelog.TrimTo(4096)) .WithDescription(thisVersionChangelog.TrimTo(4096))
.WithFooter("You may disable these messages by typing '.conf bot checkforupdates false'"); .WithFooter("You may disable these messages by typing '.conf bot checkforupdates false'");
await user.EmbedAsync(eb); await _sender.Response(user).Embed(eb).SendAsync();
}).WhenAll(); }).WhenAll();
} }
} }

View File

@@ -25,7 +25,7 @@ public sealed class SelfService : IExecNoCommand, IReadyExecutor, INService
private readonly IHttpClientFactory _httpFactory; private readonly IHttpClientFactory _httpFactory;
private readonly BotConfigService _bss; private readonly BotConfigService _bss;
private readonly IPubSub _pubSub; private readonly IPubSub _pubSub;
private readonly IEmbedBuilderService _eb; private readonly IMessageSenderService _sender;
//keys //keys
private readonly TypedKey<ActivityPubData> _activitySetKey; private readonly TypedKey<ActivityPubData> _activitySetKey;
@@ -40,7 +40,7 @@ public sealed class SelfService : IExecNoCommand, IReadyExecutor, INService
IHttpClientFactory factory, IHttpClientFactory factory,
BotConfigService bss, BotConfigService bss,
IPubSub pubSub, IPubSub pubSub,
IEmbedBuilderService eb) IMessageSenderService sender)
{ {
_cmdHandler = cmdHandler; _cmdHandler = cmdHandler;
_db = db; _db = db;
@@ -50,7 +50,7 @@ public sealed class SelfService : IExecNoCommand, IReadyExecutor, INService
_httpFactory = factory; _httpFactory = factory;
_bss = bss; _bss = bss;
_pubSub = pubSub; _pubSub = pubSub;
_eb = eb; _sender = sender;
_activitySetKey = new("activity.set"); _activitySetKey = new("activity.set");
_guildLeaveKey = new("guild.leave"); _guildLeaveKey = new("guild.leave");
@@ -225,7 +225,7 @@ public sealed class SelfService : IExecNoCommand, IReadyExecutor, INService
{ {
try try
{ {
await ownerCh.Response(_strings, _eb).Confirm(title, toSend).SendAsync(); await _sender.Response(ownerCh).Confirm(title, toSend).SendAsync();
} }
catch catch
{ {
@@ -238,7 +238,7 @@ public sealed class SelfService : IExecNoCommand, IReadyExecutor, INService
try try
{ {
if (_client.GetChannel(cid) is ITextChannel ch) if (_client.GetChannel(cid) is ITextChannel ch)
await ch.Response(_strings, _eb).Confirm(title, toSend).SendAsync(); await _sender.Response(ch).Confirm(title, toSend).SendAsync();
} }
catch catch
{ {
@@ -252,7 +252,7 @@ public sealed class SelfService : IExecNoCommand, IReadyExecutor, INService
{ {
try try
{ {
await firstOwnerChannel.Response(_strings, _eb).Confirm(title, toSend).SendAsync(); await _sender.Response(firstOwnerChannel).Confirm(title, toSend).SendAsync();
} }
catch catch
{ {

View File

@@ -22,7 +22,6 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
private readonly MuteService _mute; private readonly MuteService _mute;
private readonly ProtectionService _prot; private readonly ProtectionService _prot;
private readonly GuildTimezoneService _tz; private readonly GuildTimezoneService _tz;
private readonly IEmbedBuilderService _eb;
private readonly IMemoryCache _memoryCache; private readonly IMemoryCache _memoryCache;
private readonly ConcurrentHashSet<ulong> _ignoreMessageIds = new(); private readonly ConcurrentHashSet<ulong> _ignoreMessageIds = new();
@@ -37,20 +36,18 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
ProtectionService prot, ProtectionService prot,
GuildTimezoneService tz, GuildTimezoneService tz,
IMemoryCache memoryCache, IMemoryCache memoryCache,
IEmbedBuilderService eb,
UserPunishService punishService, UserPunishService punishService,
IMessageSenderService sender) IMessageSenderService sender)
{ {
_client = client; _client = client;
_memoryCache = memoryCache; _memoryCache = memoryCache;
_eb = eb; _sender = sender;
_strings = strings; _strings = strings;
_db = db; _db = db;
_mute = mute; _mute = mute;
_prot = prot; _prot = prot;
_tz = tz; _tz = tz;
_punishService = punishService; _punishService = punishService;
_sender = sender;
using (var uow = db.GetDbContext()) using (var uow = db.GetDbContext())
{ {
@@ -73,7 +70,6 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
_client.UserLeft += _client_UserLeft; _client.UserLeft += _client_UserLeft;
// _client.PresenceUpdated += _client_UserPresenceUpdated; // _client.PresenceUpdated += _client_UserPresenceUpdated;
_client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated; _client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated;
_client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated_TTS;
_client.GuildMemberUpdated += _client_GuildUserUpdated; _client.GuildMemberUpdated += _client_GuildUserUpdated;
_client.PresenceUpdated += _client_PresenceUpdated; _client.PresenceUpdated += _client_PresenceUpdated;
_client.UserUpdated += _client_UserUpdated; _client.UserUpdated += _client_UserUpdated;
@@ -168,11 +164,11 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
var title = GetText(logChannel.Guild, strs.thread_deleted); var title = GetText(logChannel.Guild, strs.thread_deleted);
await logChannel.EmbedAsync(new EmbedBuilder() await _sender.Response(logChannel).Embed(new EmbedBuilder()
.WithOkColor() .WithOkColor()
.WithTitle("🗑 " + title) .WithTitle("🗑 " + title)
.WithDescription($"{ch.Name} | {ch.Id}") .WithDescription($"{ch.Name} | {ch.Id}")
.WithFooter(CurrentTime(ch.Guild))); .WithFooter(CurrentTime(ch.Guild))).SendAsync();
} }
catch (Exception) catch (Exception)
{ {
@@ -198,11 +194,11 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
var title = GetText(logChannel.Guild, strs.thread_created); var title = GetText(logChannel.Guild, strs.thread_created);
await logChannel.EmbedAsync(new EmbedBuilder() await _sender.Response(logChannel).Embed(new EmbedBuilder()
.WithOkColor() .WithOkColor()
.WithTitle("🆕 " + title) .WithTitle("🆕 " + title)
.WithDescription($"{ch.Name} | {ch.Id}") .WithDescription($"{ch.Name} | {ch.Id}")
.WithFooter(CurrentTime(ch.Guild))); .WithFooter(CurrentTime(ch.Guild))).SendAsync();
} }
catch (Exception) catch (Exception)
{ {
@@ -313,7 +309,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
logSetting.UserLeftId = logSetting.UserBannedId = logSetting.UserUnbannedId = logSetting.UserUpdatedId = logSetting.UserLeftId = logSetting.UserBannedId = logSetting.UserUnbannedId = logSetting.UserUpdatedId =
logSetting.ChannelCreatedId = logSetting.ChannelDestroyedId = logSetting.ChannelUpdatedId = logSetting.ChannelCreatedId = logSetting.ChannelDestroyedId = logSetting.ChannelUpdatedId =
logSetting.LogUserPresenceId = logSetting.LogVoicePresenceId = logSetting.UserMutedId = logSetting.LogUserPresenceId = logSetting.LogVoicePresenceId = logSetting.UserMutedId =
logSetting.LogVoicePresenceTTSId = logSetting.ThreadCreatedId = logSetting.ThreadDeletedId logSetting.ThreadCreatedId = logSetting.ThreadDeletedId
= logSetting.LogWarnsId = value ? channelId : null; = logSetting.LogWarnsId = value ? channelId : null;
await uow.SaveChangesAsync(); await uow.SaveChangesAsync();
GuildLogSettings.AddOrUpdate(guildId, _ => logSetting, (_, _) => logSetting); GuildLogSettings.AddOrUpdate(guildId, _ => logSetting, (_, _) => logSetting);
@@ -339,7 +335,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
.AddField("Reason", string.IsNullOrWhiteSpace(arg.Reason) ? "-" : arg.Reason, true) .AddField("Reason", string.IsNullOrWhiteSpace(arg.Reason) ? "-" : arg.Reason, true)
.WithFooter(CurrentTime(g)); .WithFooter(CurrentTime(g));
await logChannel.EmbedAsync(embed); await _sender.Response(logChannel).Embed(embed).SendAsync();
} }
private Task _client_UserUpdated(SocketUser before, SocketUser uAfter) private Task _client_UserUpdated(SocketUser before, SocketUser uAfter)
@@ -389,7 +385,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
else else
return; return;
await logChannel.EmbedAsync(embed); await _sender.Response(logChannel).Embed(embed).SendAsync();
} }
catch catch
{ {
@@ -451,10 +447,6 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
case LogType.VoicePresence: case LogType.VoicePresence:
channelId = logSetting.LogVoicePresenceId = logSetting.LogVoicePresenceId is null ? cid : default; channelId = logSetting.LogVoicePresenceId = logSetting.LogVoicePresenceId is null ? cid : default;
break; break;
case LogType.VoicePresenceTts:
channelId = logSetting.LogVoicePresenceTTSId =
logSetting.LogVoicePresenceTTSId is null ? cid : default;
break;
case LogType.UserWarned: case LogType.UserWarned:
channelId = logSetting.LogWarnsId = logSetting.LogWarnsId is null ? cid : default; channelId = logSetting.LogWarnsId = logSetting.LogWarnsId is null ? cid : default;
break; break;
@@ -472,48 +464,6 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
return channelId is not null; return channelId is not null;
} }
private Task _client_UserVoiceStateUpdated_TTS(SocketUser iusr, SocketVoiceState before, SocketVoiceState after)
{
_ = Task.Run(async () =>
{
try
{
if (iusr is not IGuildUser usr)
return;
var beforeVch = before.VoiceChannel;
var afterVch = after.VoiceChannel;
if (beforeVch == afterVch)
return;
if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out var logSetting)
|| logSetting.LogVoicePresenceTTSId is null)
return;
ITextChannel? logChannel;
if ((logChannel = await TryGetLogChannel(usr.Guild, logSetting, LogType.VoicePresenceTts)) is null)
return;
var str = string.Empty;
if (beforeVch?.Guild == afterVch?.Guild)
str = GetText(logChannel.Guild, strs.log_vc_moved(usr.Username, beforeVch?.Name, afterVch?.Name));
else if (beforeVch is null)
str = GetText(logChannel.Guild, strs.log_vc_joined(usr.Username, afterVch?.Name));
else if (afterVch is null)
str = GetText(logChannel.Guild, strs.log_vc_left(usr.Username, beforeVch.Name));
var toDelete = await logChannel.SendMessageAsync(str, true);
toDelete.DeleteAfter(5);
}
catch
{
// ignored
}
});
return Task.CompletedTask;
}
private void MuteCommands_UserMuted( private void MuteCommands_UserMuted(
IGuildUser usr, IGuildUser usr,
IUser mod, IUser mod,
@@ -551,7 +501,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
.WithFooter(CurrentTime(usr.Guild)) .WithFooter(CurrentTime(usr.Guild))
.WithOkColor(); .WithOkColor();
await logChannel.EmbedAsync(embed); await _sender.Response(logChannel).Embed(embed).SendAsync();
} }
catch catch
{ {
@@ -601,7 +551,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
if (!string.IsNullOrWhiteSpace(reason)) if (!string.IsNullOrWhiteSpace(reason))
embed.WithDescription(reason); embed.WithDescription(reason);
await logChannel.EmbedAsync(embed); await _sender.Response(logChannel).Embed(embed).SendAsync();
} }
catch catch
{ {
@@ -653,7 +603,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
.WithFooter(CurrentTime(logChannel.Guild)) .WithFooter(CurrentTime(logChannel.Guild))
.WithOkColor(); .WithOkColor();
await logChannel.EmbedAsync(embed); await _sender.Response(logChannel).Embed(embed).SendAsync();
} }
catch catch
{ {
@@ -711,7 +661,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
.AddField(GetText(logChannel.Guild, strs.new_nick), .AddField(GetText(logChannel.Guild, strs.new_nick),
$"{after.Nickname}#{after.Discriminator}"); $"{after.Nickname}#{after.Discriminator}");
await logChannel.EmbedAsync(embed); await _sender.Response(logChannel).Embed(embed).SendAsync();
} }
else if (!before.Roles.SequenceEqual(after.Roles)) else if (!before.Roles.SequenceEqual(after.Roles))
{ {
@@ -721,7 +671,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
embed.WithAuthor("⚔ " + GetText(logChannel.Guild, strs.user_role_add)) embed.WithAuthor("⚔ " + GetText(logChannel.Guild, strs.user_role_add))
.WithDescription(string.Join(", ", diffRoles).SanitizeMentions()); .WithDescription(string.Join(", ", diffRoles).SanitizeMentions());
await logChannel.EmbedAsync(embed); await _sender.Response(logChannel).Embed(embed).SendAsync();
} }
else if (before.Roles.Count > after.Roles.Count) else if (before.Roles.Count > after.Roles.Count)
{ {
@@ -735,7 +685,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
embed.WithAuthor("⚔ " + GetText(logChannel.Guild, strs.user_role_rem)) embed.WithAuthor("⚔ " + GetText(logChannel.Guild, strs.user_role_rem))
.WithDescription(string.Join(", ", diffRoles).SanitizeMentions()); .WithDescription(string.Join(", ", diffRoles).SanitizeMentions());
await logChannel.EmbedAsync(embed); await _sender.Response(logChannel).Embed(embed).SendAsync();
} }
} }
} }
@@ -791,7 +741,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
else else
return; return;
await logChannel.EmbedAsync(embed); await _sender.Response(logChannel).Embed(embed).SendAsync();
} }
catch catch
{ {
@@ -826,11 +776,11 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
else else
title = GetText(logChannel.Guild, strs.text_chan_destroyed); title = GetText(logChannel.Guild, strs.text_chan_destroyed);
await logChannel.EmbedAsync(new EmbedBuilder() await _sender.Response(logChannel).Embed(new EmbedBuilder()
.WithOkColor() .WithOkColor()
.WithTitle("🆕 " + title) .WithTitle("🆕 " + title)
.WithDescription($"{ch.Name} | {ch.Id}") .WithDescription($"{ch.Name} | {ch.Id}")
.WithFooter(CurrentTime(ch.Guild))); .WithFooter(CurrentTime(ch.Guild))).SendAsync();
} }
catch catch
{ {
@@ -862,11 +812,11 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
else else
title = GetText(logChannel.Guild, strs.text_chan_created); title = GetText(logChannel.Guild, strs.text_chan_created);
await logChannel.EmbedAsync(new EmbedBuilder() await _sender.Response(logChannel).Embed(new EmbedBuilder()
.WithOkColor() .WithOkColor()
.WithTitle("🆕 " + title) .WithTitle("🆕 " + title)
.WithDescription($"{ch.Name} | {ch.Id}") .WithDescription($"{ch.Name} | {ch.Id}")
.WithFooter(CurrentTime(ch.Guild))); .WithFooter(CurrentTime(ch.Guild))).SendAsync();
} }
catch (Exception) catch (Exception)
{ {
@@ -975,7 +925,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
if (Uri.IsWellFormedUriString(usr.GetAvatarUrl(), UriKind.Absolute)) if (Uri.IsWellFormedUriString(usr.GetAvatarUrl(), UriKind.Absolute))
embed.WithThumbnailUrl(usr.GetAvatarUrl()); embed.WithThumbnailUrl(usr.GetAvatarUrl());
await logChannel.EmbedAsync(embed); await _sender.Response(logChannel).Embed(embed).SendAsync();
} }
catch catch
{ {
@@ -1014,7 +964,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
if (Uri.IsWellFormedUriString(usr.GetAvatarUrl(), UriKind.Absolute)) if (Uri.IsWellFormedUriString(usr.GetAvatarUrl(), UriKind.Absolute))
embed.WithThumbnailUrl(usr.GetAvatarUrl()); embed.WithThumbnailUrl(usr.GetAvatarUrl());
await logChannel.EmbedAsync(embed); await _sender.Response(logChannel).Embed(embed).SendAsync();
} }
catch (Exception) catch (Exception)
{ {
@@ -1049,7 +999,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
if (Uri.IsWellFormedUriString(usr.GetAvatarUrl(), UriKind.Absolute)) if (Uri.IsWellFormedUriString(usr.GetAvatarUrl(), UriKind.Absolute))
embed.WithThumbnailUrl(usr.GetAvatarUrl()); embed.WithThumbnailUrl(usr.GetAvatarUrl());
await logChannel.EmbedAsync(embed); await _sender.Response(logChannel).Embed(embed).SendAsync();
} }
catch (Exception) catch (Exception)
{ {
@@ -1099,7 +1049,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
if (Uri.IsWellFormedUriString(avatarUrl, UriKind.Absolute)) if (Uri.IsWellFormedUriString(avatarUrl, UriKind.Absolute))
embed.WithThumbnailUrl(usr.GetAvatarUrl()); embed.WithThumbnailUrl(usr.GetAvatarUrl());
await logChannel.EmbedAsync(embed); await _sender.Response(logChannel).Embed(embed).SendAsync();
} }
catch (Exception) catch (Exception)
{ {
@@ -1152,7 +1102,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
string.Join(", ", msg.Attachments.Select(a => a.Url))); string.Join(", ", msg.Attachments.Select(a => a.Url)));
} }
await logChannel.EmbedAsync(embed); await _sender.Response(logChannel).Embed(embed).SendAsync();
} }
catch (Exception) catch (Exception)
{ {
@@ -1212,7 +1162,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
.AddField("Id", after.Id.ToString()) .AddField("Id", after.Id.ToString())
.WithFooter(CurrentTime(channel.Guild)); .WithFooter(CurrentTime(channel.Guild));
await logChannel.EmbedAsync(embed); await _sender.Response(logChannel).Embed(embed).SendAsync();
} }
catch catch
{ {
@@ -1266,9 +1216,6 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
case LogType.VoicePresence: case LogType.VoicePresence:
id = logSetting.LogVoicePresenceId; id = logSetting.LogVoicePresenceId;
break; break;
case LogType.VoicePresenceTts:
id = logSetting.LogVoicePresenceTTSId;
break;
case LogType.UserMuted: case LogType.UserMuted:
id = logSetting.UserMutedId; id = logSetting.UserMutedId;
break; break;
@@ -1348,9 +1295,6 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
case LogType.VoicePresence: case LogType.VoicePresence:
newLogSetting.LogVoicePresenceId = null; newLogSetting.LogVoicePresenceId = null;
break; break;
case LogType.VoicePresenceTts:
newLogSetting.LogVoicePresenceTTSId = null;
break;
case LogType.UserWarned: case LogType.UserWarned:
newLogSetting.LogWarnsId = null; newLogSetting.LogWarnsId = null;
break; break;

View File

@@ -145,8 +145,6 @@ public partial class Administration
return l.LogUserPresenceId; return l.LogUserPresenceId;
case LogType.VoicePresence: case LogType.VoicePresence:
return l.LogVoicePresenceId; return l.LogVoicePresenceId;
case LogType.VoicePresenceTts:
return l.LogVoicePresenceTTSId;
case LogType.UserMuted: case LogType.UserMuted:
return l.UserMutedId; return l.UserMutedId;
case LogType.UserWarned: case LogType.UserWarned:

View File

@@ -65,11 +65,13 @@ public partial class Administration
var dmFailed = false; var dmFailed = false;
try try
{ {
await user.EmbedAsync(new EmbedBuilder() await _sender.Response(user)
.WithErrorColor() .Embed(new EmbedBuilder()
.WithDescription(GetText(strs.warned_on(ctx.Guild.ToString()))) .WithErrorColor()
.AddField(GetText(strs.moderator), ctx.User.ToString()) .WithDescription(GetText(strs.warned_on(ctx.Guild.ToString())))
.AddField(GetText(strs.reason), reason ?? "-")); .AddField(GetText(strs.moderator), ctx.User.ToString())
.AddField(GetText(strs.reason), reason ?? "-"))
.SendAsync();
} }
catch catch
{ {
@@ -84,7 +86,8 @@ public partial class Administration
catch (Exception ex) catch (Exception ex)
{ {
Log.Warning(ex, "Exception occured while warning a user"); Log.Warning(ex, "Exception occured while warning a user");
var errorEmbed = new EmbedBuilder().WithErrorColor().WithDescription(GetText(strs.cant_apply_punishment)); var errorEmbed = new EmbedBuilder().WithErrorColor()
.WithDescription(GetText(strs.cant_apply_punishment));
if (dmFailed) if (dmFailed)
errorEmbed.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user)); errorEmbed.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user));
@@ -261,9 +264,9 @@ public partial class Administration
}); });
return new EmbedBuilder() return new EmbedBuilder()
.WithOkColor() .WithOkColor()
.WithTitle(GetText(strs.warnings_list)) .WithTitle(GetText(strs.warnings_list))
.WithDescription(string.Join("\n", ws)); .WithDescription(string.Join("\n", ws));
}, },
warnings.Length, warnings.Length,
15); 15);
@@ -433,9 +436,10 @@ public partial class Administration
try try
{ {
var defaultMessage = GetText(strs.bandm(Format.Bold(ctx.Guild.Name), msg)); var defaultMessage = GetText(strs.bandm(Format.Bold(ctx.Guild.Name), msg));
var embed = await _service.GetBanUserDmEmbed(Context, guildUser, defaultMessage, msg, time.Time); var smartText =
if (embed is not null) await _service.GetBanUserDmEmbed(Context, guildUser, defaultMessage, msg, time.Time);
await guildUser.SendAsync(embed); if (smartText is not null)
await Response().User(guildUser).Text(smartText).SendAsync();
} }
catch catch
{ {
@@ -447,13 +451,13 @@ public partial class Administration
var banPrune = await _service.GetBanPruneAsync(ctx.Guild.Id) ?? 7; var banPrune = await _service.GetBanPruneAsync(ctx.Guild.Id) ?? 7;
await _mute.TimedBan(ctx.Guild, userId, time.Time, (ctx.User + " | " + msg).TrimTo(512), banPrune); await _mute.TimedBan(ctx.Guild, userId, time.Time, (ctx.User + " | " + msg).TrimTo(512), banPrune);
var toSend = new EmbedBuilder() var toSend = new EmbedBuilder()
.WithOkColor() .WithOkColor()
.WithTitle("⛔️ " + GetText(strs.banned_user)) .WithTitle("⛔️ " + GetText(strs.banned_user))
.AddField(GetText(strs.username), user?.ToString() ?? userId.ToString(), true) .AddField(GetText(strs.username), user?.ToString() ?? userId.ToString(), true)
.AddField("ID", userId.ToString(), true) .AddField("ID", userId.ToString(), true)
.AddField(GetText(strs.duration), .AddField(GetText(strs.duration),
time.Time.Humanize(3, minUnit: TimeUnit.Minute, culture: Culture), time.Time.Humanize(3, minUnit: TimeUnit.Minute, culture: Culture),
true); true);
if (dmFailed) if (dmFailed)
toSend.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user)); toSend.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user));
@@ -475,9 +479,9 @@ public partial class Administration
await ctx.Guild.AddBanAsync(userId, banPrune, (ctx.User + " | " + msg).TrimTo(512)); await ctx.Guild.AddBanAsync(userId, banPrune, (ctx.User + " | " + msg).TrimTo(512));
await ctx.Channel.EmbedAsync(new EmbedBuilder() await ctx.Channel.EmbedAsync(new EmbedBuilder()
.WithOkColor() .WithOkColor()
.WithTitle("⛔️ " + GetText(strs.banned_user)) .WithTitle("⛔️ " + GetText(strs.banned_user))
.AddField("ID", userId.ToString(), true)); .AddField("ID", userId.ToString(), true));
} }
else else
await Ban(user, msg); await Ban(user, msg);
@@ -500,7 +504,7 @@ public partial class Administration
var defaultMessage = GetText(strs.bandm(Format.Bold(ctx.Guild.Name), msg)); var defaultMessage = GetText(strs.bandm(Format.Bold(ctx.Guild.Name), msg));
var embed = await _service.GetBanUserDmEmbed(Context, user, defaultMessage, msg, null); var embed = await _service.GetBanUserDmEmbed(Context, user, defaultMessage, msg, null);
if (embed is not null) if (embed is not null)
await user.SendAsync(embed); await Response().User(user).Text(embed).SendAsync();
} }
catch catch
{ {
@@ -511,10 +515,10 @@ public partial class Administration
await ctx.Guild.AddBanAsync(user, banPrune, (ctx.User + " | " + msg).TrimTo(512)); await ctx.Guild.AddBanAsync(user, banPrune, (ctx.User + " | " + msg).TrimTo(512));
var toSend = new EmbedBuilder() var toSend = new EmbedBuilder()
.WithOkColor() .WithOkColor()
.WithTitle("⛔️ " + GetText(strs.banned_user)) .WithTitle("⛔️ " + GetText(strs.banned_user))
.AddField(GetText(strs.username), user.ToString(), true) .AddField(GetText(strs.username), user.ToString(), true)
.AddField("ID", user.Id.ToString(), true); .AddField("ID", user.Id.ToString(), true);
if (dmFailed) if (dmFailed)
toSend.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user)); toSend.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user));
@@ -594,19 +598,19 @@ public partial class Administration
private async Task InternalBanMessageTest(string reason, TimeSpan? duration) private async Task InternalBanMessageTest(string reason, TimeSpan? duration)
{ {
var defaultMessage = GetText(strs.bandm(Format.Bold(ctx.Guild.Name), reason)); var defaultMessage = GetText(strs.bandm(Format.Bold(ctx.Guild.Name), reason));
var embed = await _service.GetBanUserDmEmbed(Context, var smartText = await _service.GetBanUserDmEmbed(Context,
(IGuildUser)ctx.User, (IGuildUser)ctx.User,
defaultMessage, defaultMessage,
reason, reason,
duration); duration);
if (embed is null) if (smartText is null)
await Response().Confirm(strs.banmsg_disabled).SendAsync(); await Response().Confirm(strs.banmsg_disabled).SendAsync();
else else
{ {
try try
{ {
await ctx.User.SendAsync(embed); await Response().User(ctx.User).Text(smartText).SendAsync();
} }
catch (Exception) catch (Exception)
{ {
@@ -692,7 +696,7 @@ public partial class Administration
{ {
await Response() await Response()
.Channel(await user.CreateDMChannelAsync()) .Channel(await user.CreateDMChannelAsync())
.Error(GetText(strs.sbdm(Format.Bold(ctx.Guild.Name), msg))) .Error(strs.sbdm(Format.Bold(ctx.Guild.Name), msg))
.SendAsync(); .SendAsync();
} }
catch catch
@@ -706,10 +710,10 @@ public partial class Administration
catch { await ctx.Guild.RemoveBanAsync(user); } catch { await ctx.Guild.RemoveBanAsync(user); }
var toSend = new EmbedBuilder() var toSend = new EmbedBuilder()
.WithOkColor() .WithOkColor()
.WithTitle("☣ " + GetText(strs.sb_user)) .WithTitle("☣ " + GetText(strs.sb_user))
.AddField(GetText(strs.username), user.ToString(), true) .AddField(GetText(strs.username), user.ToString(), true)
.AddField("ID", user.Id.ToString(), true); .AddField("ID", user.Id.ToString(), true);
if (dmFailed) if (dmFailed)
toSend.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user)); toSend.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user));
@@ -761,10 +765,10 @@ public partial class Administration
await user.KickAsync((ctx.User + " | " + msg).TrimTo(512)); await user.KickAsync((ctx.User + " | " + msg).TrimTo(512));
var toSend = new EmbedBuilder() var toSend = new EmbedBuilder()
.WithOkColor() .WithOkColor()
.WithTitle(GetText(strs.kicked_user)) .WithTitle(GetText(strs.kicked_user))
.AddField(GetText(strs.username), user.ToString(), true) .AddField(GetText(strs.username), user.ToString(), true)
.AddField("ID", user.Id.ToString(), true); .AddField("ID", user.Id.ToString(), true);
if (dmFailed) if (dmFailed)
toSend.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user)); toSend.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user));
@@ -792,9 +796,11 @@ public partial class Administration
try try
{ {
var dmMessage = GetText(strs.timeoutdm(Format.Bold(ctx.Guild.Name), msg)); var dmMessage = GetText(strs.timeoutdm(Format.Bold(ctx.Guild.Name), msg));
await user.EmbedAsync(new EmbedBuilder() await _sender.Response(user)
.WithPendingColor() .Embed(new EmbedBuilder()
.WithDescription(dmMessage)); .WithPendingColor()
.WithDescription(dmMessage))
.SendAsync();
} }
catch catch
{ {
@@ -804,10 +810,10 @@ public partial class Administration
await user.SetTimeOutAsync(time.Time); await user.SetTimeOutAsync(time.Time);
var toSend = new EmbedBuilder() var toSend = new EmbedBuilder()
.WithOkColor() .WithOkColor()
.WithTitle("⏳ " + GetText(strs.timedout_user)) .WithTitle("⏳ " + GetText(strs.timedout_user))
.AddField(GetText(strs.username), user.ToString(), true) .AddField(GetText(strs.username), user.ToString(), true)
.AddField("ID", user.Id.ToString(), true); .AddField("ID", user.Id.ToString(), true);
if (dmFailed) if (dmFailed)
toSend.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user)); toSend.WithFooter("⚠️ " + GetText(strs.unable_to_dm_user));
@@ -865,9 +871,9 @@ public partial class Administration
missStr = "-"; missStr = "-";
var toSend = new EmbedBuilder() var toSend = new EmbedBuilder()
.WithDescription(GetText(strs.mass_ban_in_progress(banning.Count))) .WithDescription(GetText(strs.mass_ban_in_progress(banning.Count)))
.AddField(GetText(strs.invalid(missing.Count)), missStr) .AddField(GetText(strs.invalid(missing.Count)), missStr)
.WithPendingColor(); .WithPendingColor();
var banningMessage = await Response().Embed(toSend).SendAsync(); var banningMessage = await Response().Embed(toSend).SendAsync();
@@ -885,11 +891,11 @@ public partial class Administration
} }
await banningMessage.ModifyAsync(x => x.Embed = new EmbedBuilder() await banningMessage.ModifyAsync(x => x.Embed = new EmbedBuilder()
.WithDescription( .WithDescription(
GetText(strs.mass_ban_completed(banning.Count()))) GetText(strs.mass_ban_completed(banning.Count())))
.AddField(GetText(strs.invalid(missing.Count)), missStr) .AddField(GetText(strs.invalid(missing.Count)), missStr)
.WithOkColor() .WithOkColor()
.Build()); .Build());
} }
[Cmd] [Cmd]
@@ -910,10 +916,10 @@ public partial class Administration
//send a message but don't wait for it //send a message but don't wait for it
var banningMessageTask = ctx.Channel.EmbedAsync(new EmbedBuilder() var banningMessageTask = ctx.Channel.EmbedAsync(new EmbedBuilder()
.WithDescription( .WithDescription(
GetText(strs.mass_kill_in_progress(bans.Count()))) GetText(strs.mass_kill_in_progress(bans.Count())))
.AddField(GetText(strs.invalid(missing)), missStr) .AddField(GetText(strs.invalid(missing)), missStr)
.WithPendingColor()); .WithPendingColor());
var banPrune = await _service.GetBanPruneAsync(ctx.Guild.Id) ?? 7; var banPrune = await _service.GetBanPruneAsync(ctx.Guild.Id) ?? 7;
//do the banning //do the banning
@@ -930,11 +936,11 @@ public partial class Administration
var banningMessage = await banningMessageTask; var banningMessage = await banningMessageTask;
await banningMessage.ModifyAsync(x => x.Embed = new EmbedBuilder() await banningMessage.ModifyAsync(x => x.Embed = new EmbedBuilder()
.WithDescription( .WithDescription(
GetText(strs.mass_kill_completed(bans.Count()))) GetText(strs.mass_kill_completed(bans.Count())))
.AddField(GetText(strs.invalid(missing)), missStr) .AddField(GetText(strs.invalid(missing)), missStr)
.WithOkColor() .WithOkColor()
.Build()); .Build());
} }
public class WarnExpireOptions : INadekoCommandOptions public class WarnExpireOptions : INadekoCommandOptions

View File

@@ -71,7 +71,7 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
private readonly IBotStrings _strings; private readonly IBotStrings _strings;
private readonly IBot _bot; private readonly IBot _bot;
private readonly IPubSub _pubSub; private readonly IPubSub _pubSub;
private readonly IEmbedBuilderService _eb; private readonly IMessageSenderService _sender;
private readonly IReplacementService _repSvc; private readonly IReplacementService _repSvc;
private readonly Random _rng; private readonly Random _rng;
@@ -85,7 +85,7 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
DiscordSocketClient client, DiscordSocketClient client,
ICommandHandler cmd, ICommandHandler cmd,
IPubSub pubSub, IPubSub pubSub,
IEmbedBuilderService eb, IMessageSenderService sender,
IReplacementService repSvc, IReplacementService repSvc,
IPermissionChecker permChecker) IPermissionChecker permChecker)
{ {
@@ -95,7 +95,7 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
_strings = strings; _strings = strings;
_bot = bot; _bot = bot;
_pubSub = pubSub; _pubSub = pubSub;
_eb = eb; _sender = sender;
_repSvc = repSvc; _repSvc = repSvc;
_permChecker = permChecker; _permChecker = permChecker;
_rng = new NadekoRandom(); _rng = new NadekoRandom();
@@ -265,8 +265,7 @@ public sealed class NadekoExpressionsService : IExecOnMessage, IReadyExecutor
try try
{ {
await msg.Channel await _sender.Response(msg.Channel)
.Response(_strings, _eb)
.Error(permissionMessage) .Error(permissionMessage)
.SendAsync(); .SendAsync();
} }

View File

@@ -169,7 +169,7 @@ public partial class Gambling
} }
else else
await Response() await Response()
.Confirm(GetText(strs.animal_race_join(ctx.User.Mention, user.Animal.Icon))) .Confirm(strs.animal_race_join(ctx.User.Mention, user.Animal.Icon))
.SendAsync(); .SendAsync();
} }
catch (ArgumentOutOfRangeException) catch (ArgumentOutOfRangeException)

View File

@@ -65,7 +65,7 @@ public partial class Gambling
try try
{ {
await ctx.User.EmbedAsync(eb); await Response().User(ctx.User).Embed(eb).SendAsync();
await ctx.OkAsync(); await ctx.OkAsync();
} }
catch catch

View File

@@ -109,7 +109,7 @@ public partial class Gambling
RepostCounter++; RepostCounter++;
if (RepostCounter == 0) if (RepostCounter == 0)
{ {
try { msg = await ctx.Channel.SendMessageAsync("", embed: (Embed)msg.Embeds.First()); } try { msg = await Response().Embed(msg.Embeds.First().ToEmbedBuilder()).SendAsync(); }
catch { } catch { }
} }
} }

View File

@@ -12,12 +12,15 @@ public class CurrencyEventsService : INService
private readonly GamblingConfigService _configService; private readonly GamblingConfigService _configService;
private readonly ConcurrentDictionary<ulong, ICurrencyEvent> _events = new(); private readonly ConcurrentDictionary<ulong, ICurrencyEvent> _events = new();
private readonly IMessageSenderService _sender;
public CurrencyEventsService(DiscordSocketClient client, ICurrencyService cs, GamblingConfigService configService) public CurrencyEventsService(DiscordSocketClient client, ICurrencyService cs, GamblingConfigService configService,
IMessageSenderService sender)
{ {
_client = client; _client = client;
_cs = cs; _cs = cs;
_configService = configService; _configService = configService;
_sender = sender;
} }
public async Task<bool> TryCreateEventAsync( public async Task<bool> TryCreateEventAsync(
@@ -34,9 +37,9 @@ public class CurrencyEventsService : INService
ICurrencyEvent ce; ICurrencyEvent ce;
if (type == CurrencyEvent.Type.Reaction) if (type == CurrencyEvent.Type.Reaction)
ce = new ReactionEvent(_client, _cs, g, ch, opts, _configService.Data, embed); ce = new ReactionEvent(_client, _cs, g, ch, opts, _configService.Data, _sender, embed);
else if (type == CurrencyEvent.Type.GameStatus) else if (type == CurrencyEvent.Type.GameStatus)
ce = new GameStatusEvent(_client, _cs, g, ch, opts, embed); ce = new GameStatusEvent(_client, _cs, g, ch, opts, _sender, embed);
else else
return false; return false;

View File

@@ -36,6 +36,7 @@ public class GameStatusEvent : ICurrencyEvent
private readonly object _stopLock = new(); private readonly object _stopLock = new();
private readonly object _potLock = new(); private readonly object _potLock = new();
private readonly IMessageSenderService _sender;
public GameStatusEvent( public GameStatusEvent(
DiscordSocketClient client, DiscordSocketClient client,
@@ -43,6 +44,7 @@ public class GameStatusEvent : ICurrencyEvent
SocketGuild g, SocketGuild g,
ITextChannel ch, ITextChannel ch,
EventOptions opt, EventOptions opt,
IMessageSenderService sender,
Func<CurrencyEvent.Type, EventOptions, long, EmbedBuilder> embedFunc) Func<CurrencyEvent.Type, EventOptions, long, EmbedBuilder> embedFunc)
{ {
_client = client; _client = client;
@@ -54,6 +56,7 @@ public class GameStatusEvent : ICurrencyEvent
_isPotLimited = PotSize > 0; _isPotLimited = PotSize > 0;
_channel = ch; _channel = ch;
_opts = opt; _opts = opt;
_sender = sender;
// generate code // generate code
_code = new(_sneakyGameStatusChars.Shuffle().Take(5).ToArray()); _code = new(_sneakyGameStatusChars.Shuffle().Take(5).ToArray());
@@ -106,7 +109,7 @@ public class GameStatusEvent : ICurrencyEvent
public async Task StartEvent() public async Task StartEvent()
{ {
msg = await _channel.EmbedAsync(GetEmbed(_opts.PotSize)); msg = await _sender.Response(_channel).Embed(GetEmbed(_opts.PotSize)).SendAsync();
await _client.SetGameAsync(_code); await _client.SetGameAsync(_code);
_client.MessageDeleted += OnMessageDeleted; _client.MessageDeleted += OnMessageDeleted;
_client.MessageReceived += HandleMessage; _client.MessageReceived += HandleMessage;

View File

@@ -30,6 +30,7 @@ public class ReactionEvent : ICurrencyEvent
private readonly object _stopLock = new(); private readonly object _stopLock = new();
private readonly object _potLock = new(); private readonly object _potLock = new();
private readonly IMessageSenderService _sender;
public ReactionEvent( public ReactionEvent(
DiscordSocketClient client, DiscordSocketClient client,
@@ -38,6 +39,7 @@ public class ReactionEvent : ICurrencyEvent
ITextChannel ch, ITextChannel ch,
EventOptions opt, EventOptions opt,
GamblingConfig config, GamblingConfig config,
IMessageSenderService sender,
Func<CurrencyEvent.Type, EventOptions, long, EmbedBuilder> embedFunc) Func<CurrencyEvent.Type, EventOptions, long, EmbedBuilder> embedFunc)
{ {
_client = client; _client = client;
@@ -51,6 +53,7 @@ public class ReactionEvent : ICurrencyEvent
_noRecentlyJoinedServer = false; _noRecentlyJoinedServer = false;
_opts = opt; _opts = opt;
_config = config; _config = config;
_sender = sender;
_t = new(OnTimerTick, null, Timeout.InfiniteTimeSpan, TimeSpan.FromSeconds(2)); _t = new(OnTimerTick, null, Timeout.InfiniteTimeSpan, TimeSpan.FromSeconds(2));
if (_opts.Hours > 0) if (_opts.Hours > 0)
@@ -102,7 +105,7 @@ public class ReactionEvent : ICurrencyEvent
emote = parsedEmote; emote = parsedEmote;
else else
emote = new Emoji(_config.Currency.Sign); emote = new Emoji(_config.Currency.Sign);
msg = await _channel.EmbedAsync(GetEmbed(_opts.PotSize)); msg = await _sender.Response(_channel).Embed(GetEmbed(_opts.PotSize)).SendAsync();
await msg.AddReactionAsync(emote); await msg.AddReactionAsync(emote);
_client.MessageDeleted += OnMessageDeleted; _client.MessageDeleted += OnMessageDeleted;
_client.ReactionAdded += HandleReaction; _client.ReactionAdded += HandleReaction;

View File

@@ -74,7 +74,7 @@ public partial class Gambling : GamblingModule<GamblingService>
var stats = await _gamblingTxTracker.GetAllAsync(); var stats = await _gamblingTxTracker.GetAllAsync();
var eb = new EmbedBuilder() var eb = new EmbedBuilder()
.WithOkColor(); .WithOkColor();
var str = "` Feature `` Bet ``Paid Out`` RoI `\n"; var str = "` Feature `` Bet ``Paid Out`` RoI `\n";
str += "――――――――――――――――――――\n"; str += "――――――――――――――――――――\n";
@@ -119,15 +119,15 @@ public partial class Gambling : GamblingModule<GamblingService>
// [21:03] Bob Page: Kinda remids me of US economy // [21:03] Bob Page: Kinda remids me of US economy
var embed = new EmbedBuilder() var embed = new EmbedBuilder()
.WithTitle(GetText(strs.economy_state)) .WithTitle(GetText(strs.economy_state))
.AddField(GetText(strs.currency_owned), N(ec.Cash - ec.Bot)) .AddField(GetText(strs.currency_owned), N(ec.Cash - ec.Bot))
.AddField(GetText(strs.currency_one_percent), (onePercent * 100).ToString("F2") + "%") .AddField(GetText(strs.currency_one_percent), (onePercent * 100).ToString("F2") + "%")
.AddField(GetText(strs.currency_planted), N(ec.Planted)) .AddField(GetText(strs.currency_planted), N(ec.Planted))
.AddField(GetText(strs.owned_waifus_total), N(ec.Waifus)) .AddField(GetText(strs.owned_waifus_total), N(ec.Waifus))
.AddField(GetText(strs.bot_currency), N(ec.Bot)) .AddField(GetText(strs.bot_currency), N(ec.Bot))
.AddField(GetText(strs.bank_accounts), N(ec.Bank)) .AddField(GetText(strs.bank_accounts), N(ec.Bank))
.AddField(GetText(strs.total), N(ec.Cash + ec.Planted + ec.Waifus + ec.Bank)) .AddField(GetText(strs.total), N(ec.Cash + ec.Planted + ec.Waifus + ec.Bank))
.WithOkColor(); .WithOkColor();
// ec.Cash already contains ec.Bot as it's the total of all values in the CurrencyAmount column of the DiscordUser table // ec.Cash already contains ec.Bot as it's the total of all values in the CurrencyAmount column of the DiscordUser table
await Response().Embed(embed).SendAsync(); await Response().Embed(embed).SendAsync();
@@ -151,7 +151,7 @@ public partial class Gambling : GamblingModule<GamblingService>
GetText(strs.timely_time), GetText(strs.timely_time),
ReminderType.Timely); ReminderType.Timely);
await smc.RespondConfirmAsync(_eb, GetText(strs.remind_timely(tt)), ephemeral: true); await smc.RespondConfirmAsync(_sender, GetText(strs.remind_timely(tt)), ephemeral: true);
} }
private NadekoInteraction CreateRemindMeInteraction(int period) private NadekoInteraction CreateRemindMeInteraction(int period)
@@ -311,9 +311,9 @@ public partial class Gambling : GamblingModule<GamblingService>
} }
var embed = new EmbedBuilder() var embed = new EmbedBuilder()
.WithTitle(GetText(strs.transactions(((SocketGuild)ctx.Guild)?.GetUser(userId)?.ToString() .WithTitle(GetText(strs.transactions(((SocketGuild)ctx.Guild)?.GetUser(userId)?.ToString()
?? $"{userId}"))) ?? $"{userId}")))
.WithOkColor(); .WithOkColor();
var sb = new StringBuilder(); var sb = new StringBuilder();
foreach (var tr in trs) foreach (var tr in trs)
@@ -415,7 +415,7 @@ public partial class Gambling : GamblingModule<GamblingService>
await N(balance) await N(balance)
.Pipe(strs.bank_balance) .Pipe(strs.bank_balance)
.Pipe(GetText) .Pipe(GetText)
.Pipe(text => smc.RespondConfirmAsync(_eb, text, ephemeral: true)); .Pipe(text => smc.RespondConfirmAsync(_sender, text, ephemeral: true));
} }
private NadekoInteraction CreateCashInteraction() private NadekoInteraction CreateCashInteraction()
@@ -460,7 +460,7 @@ public partial class Gambling : GamblingModule<GamblingService>
return; return;
} }
if (!await _cs.TransferAsync(_eb, ctx.User, receiver, amount, msg, N(amount))) if (!await _cs.TransferAsync(_sender, ctx.User, receiver, amount, msg, N(amount)))
{ {
await Response().Error(strs.not_enough(CurrencySign)).SendAsync(); await Response().Error(strs.not_enough(CurrencySign)).SendAsync();
return; return;
@@ -732,10 +732,10 @@ public partial class Gambling : GamblingModule<GamblingService>
} }
var eb = new EmbedBuilder() var eb = new EmbedBuilder()
.WithAuthor(ctx.User) .WithAuthor(ctx.User)
.WithDescription(Format.Bold(str)) .WithDescription(Format.Bold(str))
.AddField(GetText(strs.roll2), result.Roll.ToString(CultureInfo.InvariantCulture)) .AddField(GetText(strs.roll2), result.Roll.ToString(CultureInfo.InvariantCulture))
.WithOkColor(); .WithOkColor();
await Response().Embed(eb).SendAsync(); await Response().Embed(eb).SendAsync();
} }
@@ -923,11 +923,11 @@ public partial class Gambling : GamblingModule<GamblingService>
} }
var eb = new EmbedBuilder() var eb = new EmbedBuilder()
.WithOkColor() .WithOkColor()
.WithDescription(sb.ToString()) .WithDescription(sb.ToString())
.AddField(GetText(strs.multiplier), $"{result.Multiplier:0.##}x", true) .AddField(GetText(strs.multiplier), $"{result.Multiplier:0.##}x", true)
.AddField(GetText(strs.won), $"{(long)result.Won}", true) .AddField(GetText(strs.won), $"{(long)result.Won}", true)
.WithAuthor(ctx.User); .WithAuthor(ctx.User);
await Response().Embed(eb).SendAsync(); await Response().Embed(eb).SendAsync();

View File

@@ -46,8 +46,8 @@ public partial class Gambling
using var uow = _db.GetDbContext(); using var uow = _db.GetDbContext();
var entries = uow.GuildConfigsForId(ctx.Guild.Id, var entries = uow.GuildConfigsForId(ctx.Guild.Id,
set => set.Include(x => x.ShopEntries).ThenInclude(x => x.Items)) set => set.Include(x => x.ShopEntries).ThenInclude(x => x.Items))
.ShopEntries.ToIndexed(); .ShopEntries.ToIndexed();
return ctx.SendPaginatedConfirmAsync(page, return ctx.SendPaginatedConfirmAsync(page,
curPage => curPage =>
{ {
@@ -116,7 +116,9 @@ public partial class Gambling
var guser = (IGuildUser)ctx.User; var guser = (IGuildUser)ctx.User;
if (!guser.RoleIds.Contains(reqRoleId)) if (!guser.RoleIds.Contains(reqRoleId))
{ {
await Response().Error(strs.shop_item_req_role_unfulfilled(Format.Bold(role.ToString()))).SendAsync(); await Response()
.Error(strs.shop_item_req_role_unfulfilled(Format.Bold(role.ToString())))
.SendAsync();
return; return;
} }
} }
@@ -178,17 +180,20 @@ public partial class Gambling
await using (var uow = _db.GetDbContext()) await using (var uow = _db.GetDbContext())
{ {
uow.Set<ShopEntryItem>().Remove(item); uow.Set<ShopEntryItem>().Remove(item);
uow.SaveChanges(); await uow.SaveChangesAsync();
} }
try try
{ {
await ctx.User.EmbedAsync(new EmbedBuilder() await Response()
.WithOkColor() .User(ctx.User)
.WithTitle(GetText(strs.shop_purchase(ctx.Guild.Name))) .Embed(new EmbedBuilder()
.AddField(GetText(strs.item), item.Text) .WithOkColor()
.AddField(GetText(strs.price), entry.Price.ToString(), true) .WithTitle(GetText(strs.shop_purchase(ctx.Guild.Name)))
.AddField(GetText(strs.name), entry.Name, true)); .AddField(GetText(strs.item), item.Text)
.AddField(GetText(strs.price), entry.Price.ToString(), true)
.AddField(GetText(strs.name), entry.Name, true))
.SendAsync();
await _cs.AddAsync(entry.AuthorId, await _cs.AddAsync(entry.AuthorId,
GetProfitAmount(entry.Price), GetProfitAmount(entry.Price),
@@ -200,9 +205,9 @@ public partial class Gambling
await using (var uow = _db.GetDbContext()) await using (var uow = _db.GetDbContext())
{ {
var entries = new IndexedCollection<ShopEntry>(uow.GuildConfigsForId(ctx.Guild.Id, var entries = new IndexedCollection<ShopEntry>(uow.GuildConfigsForId(ctx.Guild.Id,
set => set.Include(x => x.ShopEntries) set => set.Include(x => x.ShopEntries)
.ThenInclude(x => x.Items)) .ThenInclude(x => x.Items))
.ShopEntries); .ShopEntries);
entry = entries.ElementAtOrDefault(index); entry = entries.ElementAtOrDefault(index);
if (entry is not null) if (entry is not null)
{ {
@@ -242,9 +247,9 @@ public partial class Gambling
{ {
var cmd = entry.Command.Replace("%you%", ctx.User.Id.ToString()); var cmd = entry.Command.Replace("%you%", ctx.User.Id.ToString());
var eb = new EmbedBuilder() var eb = new EmbedBuilder()
.WithPendingColor() .WithPendingColor()
.WithTitle("Executing shop command") .WithTitle("Executing shop command")
.WithDescription(cmd); .WithDescription(cmd);
var msgTask = Response().Embed(eb).SendAsync(); var msgTask = Response().Embed(eb).SendAsync();
@@ -264,9 +269,9 @@ public partial class Gambling
{ {
var pendingMsg = await msgTask; var pendingMsg = await msgTask;
await pendingMsg.EditAsync(SmartEmbedText.FromEmbed(eb await pendingMsg.EditAsync(SmartEmbedText.FromEmbed(eb
.WithOkColor() .WithOkColor()
.WithTitle("Shop command executed") .WithTitle("Shop command executed")
.Build())); .Build()));
} }
catch catch
{ {
@@ -314,9 +319,9 @@ public partial class Gambling
await using (var uow = _db.GetDbContext()) await using (var uow = _db.GetDbContext())
{ {
var entries = new IndexedCollection<ShopEntry>(uow.GuildConfigsForId(ctx.Guild.Id, var entries = new IndexedCollection<ShopEntry>(uow.GuildConfigsForId(ctx.Guild.Id,
set => set.Include(x => x.ShopEntries) set => set.Include(x => x.ShopEntries)
.ThenInclude(x => x.Items)) .ThenInclude(x => x.Items))
.ShopEntries) .ShopEntries)
{ {
entry entry
}; };
@@ -346,9 +351,9 @@ public partial class Gambling
await using (var uow = _db.GetDbContext()) await using (var uow = _db.GetDbContext())
{ {
var entries = new IndexedCollection<ShopEntry>(uow.GuildConfigsForId(ctx.Guild.Id, var entries = new IndexedCollection<ShopEntry>(uow.GuildConfigsForId(ctx.Guild.Id,
set => set.Include(x => x.ShopEntries) set => set.Include(x => x.ShopEntries)
.ThenInclude(x => x.Items)) .ThenInclude(x => x.Items))
.ShopEntries) .ShopEntries)
{ {
entry entry
}; };
@@ -377,9 +382,9 @@ public partial class Gambling
await using (var uow = _db.GetDbContext()) await using (var uow = _db.GetDbContext())
{ {
var entries = new IndexedCollection<ShopEntry>(uow.GuildConfigsForId(ctx.Guild.Id, var entries = new IndexedCollection<ShopEntry>(uow.GuildConfigsForId(ctx.Guild.Id,
set => set.Include(x => x.ShopEntries) set => set.Include(x => x.ShopEntries)
.ThenInclude(x => x.Items)) .ThenInclude(x => x.Items))
.ShopEntries); .ShopEntries);
entry = entries.ElementAtOrDefault(index); entry = entries.ElementAtOrDefault(index);
if (entry is not null && (rightType = entry.Type == ShopEntryType.List)) if (entry is not null && (rightType = entry.Type == ShopEntryType.List))
{ {
@@ -531,27 +536,27 @@ public partial class Gambling
if (entry.Type == ShopEntryType.Role) if (entry.Type == ShopEntryType.Role)
{ {
return embed return embed
.AddField(GetText(strs.name), .AddField(GetText(strs.name),
GetText(strs.shop_role(Format.Bold(ctx.Guild.GetRole(entry.RoleId)?.Name GetText(strs.shop_role(Format.Bold(ctx.Guild.GetRole(entry.RoleId)?.Name
?? "MISSING_ROLE"))), ?? "MISSING_ROLE"))),
true) true)
.AddField(GetText(strs.price), N(entry.Price), true) .AddField(GetText(strs.price), N(entry.Price), true)
.AddField(GetText(strs.type), entry.Type.ToString(), true); .AddField(GetText(strs.type), entry.Type.ToString(), true);
} }
if (entry.Type == ShopEntryType.List) if (entry.Type == ShopEntryType.List)
{ {
return embed.AddField(GetText(strs.name), entry.Name, true) return embed.AddField(GetText(strs.name), entry.Name, true)
.AddField(GetText(strs.price), N(entry.Price), true) .AddField(GetText(strs.price), N(entry.Price), true)
.AddField(GetText(strs.type), GetText(strs.random_unique_item), true); .AddField(GetText(strs.type), GetText(strs.random_unique_item), true);
} }
else if (entry.Type == ShopEntryType.Command) else if (entry.Type == ShopEntryType.Command)
{ {
return embed return embed
.AddField(GetText(strs.name), Format.Code(entry.Command), true) .AddField(GetText(strs.name), Format.Code(entry.Command), true)
.AddField(GetText(strs.price), N(entry.Price), true) .AddField(GetText(strs.price), N(entry.Price), true)
.AddField(GetText(strs.type), entry.Type.ToString(), true); .AddField(GetText(strs.type), entry.Type.ToString(), true);
} }
//else if (entry.Type == ShopEntryType.Infinite_List) //else if (entry.Type == ShopEntryType.Infinite_List)

View File

@@ -20,9 +20,7 @@ public class ChatterBotService : IExecOnMessage
private readonly DiscordSocketClient _client; private readonly DiscordSocketClient _client;
private readonly IPermissionChecker _perms; private readonly IPermissionChecker _perms;
private readonly CommandHandler _cmd; private readonly CommandHandler _cmd;
private readonly IBotStrings _strings;
private readonly IBotCredentials _creds; private readonly IBotCredentials _creds;
private readonly IEmbedBuilderService _eb;
private readonly IHttpClientFactory _httpFactory; private readonly IHttpClientFactory _httpFactory;
private readonly IPatronageService _ps; private readonly IPatronageService _ps;
private readonly GamesConfigService _gcs; private readonly GamesConfigService _gcs;
@@ -33,10 +31,8 @@ public class ChatterBotService : IExecOnMessage
IPermissionChecker perms, IPermissionChecker perms,
IBot bot, IBot bot,
CommandHandler cmd, CommandHandler cmd,
IBotStrings strings,
IHttpClientFactory factory, IHttpClientFactory factory,
IBotCredentials creds, IBotCredentials creds,
IEmbedBuilderService eb,
IPatronageService ps, IPatronageService ps,
GamesConfigService gcs, GamesConfigService gcs,
IMessageSenderService sender) IMessageSenderService sender)
@@ -44,14 +40,12 @@ public class ChatterBotService : IExecOnMessage
_client = client; _client = client;
_perms = perms; _perms = perms;
_cmd = cmd; _cmd = cmd;
_strings = strings;
_creds = creds; _creds = creds;
_eb = eb; _sender = sender;
_httpFactory = factory; _httpFactory = factory;
_ps = ps; _ps = ps;
_perms = perms; _perms = perms;
_gcs = gcs; _gcs = gcs;
_sender = sender;
_flKey = new FeatureLimitKey() _flKey = new FeatureLimitKey()
{ {
@@ -166,8 +160,7 @@ public class ChatterBotService : IExecOnMessage
{ {
if (ql.Quota == 0) if (ql.Quota == 0)
{ {
await channel await _sender.Response(channel)
.Response(_strings, _eb)
.Error(null, .Error(null,
text: text:
"In order to use the cleverbot feature, the owner of this server should be [Patron Tier X](https://patreon.com/join/nadekobot) on patreon.", "In order to use the cleverbot feature, the owner of this server should be [Patron Tier X](https://patreon.com/join/nadekobot) on patreon.",
@@ -178,7 +171,7 @@ public class ChatterBotService : IExecOnMessage
return true; return true;
} }
await channel.Response(_strings, _eb) await _sender.Response(channel)
.Error( .Error(
null!, null!,
$"You've reached your quota limit of **{ql.Quota}** responses {ql.QuotaPeriod.ToFullName()} for the cleverbot feature.", $"You've reached your quota limit of **{ql.Quota}** responses {ql.QuotaPeriod.ToFullName()} for the cleverbot feature.",

View File

@@ -23,7 +23,7 @@ public partial class Games
/-\ /-\
"""; """;
public static EmbedBuilder GetEmbed(IEmbedBuilderService eb, HangmanGame.State state) public static EmbedBuilder GetEmbed(HangmanGame.State state)
{ {
if (state.Phase == HangmanGame.Phase.Running) if (state.Phase == HangmanGame.Phase.Running)
{ {
@@ -60,7 +60,7 @@ public partial class Games
return; return;
} }
var eb = GetEmbed(_eb, hangman); var eb = GetEmbed(hangman);
eb.WithDescription(GetText(strs.hangman_game_started)); eb.WithDescription(GetText(strs.hangman_game_started));
await Response().Embed(eb).SendAsync(); await Response().Embed(eb).SendAsync();
} }

View File

@@ -9,7 +9,7 @@ public sealed class HangmanService : IHangmanService, IExecNoCommand
{ {
private readonly ConcurrentDictionary<ulong, HangmanGame> _hangmanGames = new(); private readonly ConcurrentDictionary<ulong, HangmanGame> _hangmanGames = new();
private readonly IHangmanSource _source; private readonly IHangmanSource _source;
private readonly IEmbedBuilderService _eb; private readonly IMessageSenderService _sender;
private readonly GamesConfigService _gcs; private readonly GamesConfigService _gcs;
private readonly ICurrencyService _cs; private readonly ICurrencyService _cs;
private readonly IMemoryCache _cdCache; private readonly IMemoryCache _cdCache;
@@ -17,13 +17,13 @@ public sealed class HangmanService : IHangmanService, IExecNoCommand
public HangmanService( public HangmanService(
IHangmanSource source, IHangmanSource source,
IEmbedBuilderService eb, IMessageSenderService sender,
GamesConfigService gcs, GamesConfigService gcs,
ICurrencyService cs, ICurrencyService cs,
IMemoryCache cdCache) IMemoryCache cdCache)
{ {
_source = source; _source = source;
_eb = eb; _sender = sender;
_gcs = gcs; _gcs = gcs;
_cs = cs; _cs = cs;
_cdCache = cdCache; _cdCache = cdCache;
@@ -116,7 +116,7 @@ public sealed class HangmanService : IHangmanService, IExecNoCommand
string content, string content,
HangmanGame.State state) HangmanGame.State state)
{ {
var embed = Games.HangmanCommands.GetEmbed(_eb, state); var embed = Games.HangmanCommands.GetEmbed(state);
if (state.GuessResult == HangmanGame.GuessResult.Guess) if (state.GuessResult == HangmanGame.GuessResult.Guess)
embed.WithDescription($"{user} guessed the letter {content}!").WithOkColor(); embed.WithDescription($"{user} guessed the letter {content}!").WithOkColor();
else if (state.GuessResult == HangmanGame.GuessResult.Incorrect && state.Failed) else if (state.GuessResult == HangmanGame.GuessResult.Incorrect && state.Failed)
@@ -131,6 +131,6 @@ public sealed class HangmanService : IHangmanService, IExecNoCommand
if (!string.IsNullOrWhiteSpace(state.ImageUrl) && Uri.IsWellFormedUriString(state.ImageUrl, UriKind.Absolute)) if (!string.IsNullOrWhiteSpace(state.ImageUrl) && Uri.IsWellFormedUriString(state.ImageUrl, UriKind.Absolute))
embed.WithImageUrl(state.ImageUrl); embed.WithImageUrl(state.ImageUrl);
return channel.EmbedAsync(embed); return _sender.Response(channel).Embed(embed).SendAsync();
} }
} }

View File

@@ -78,10 +78,11 @@ public class TypingGame
var time = _options.StartTime; var time = _options.StartTime;
var msg = await Channel.SendMessageAsync($"Starting new typing contest in **{time}**..."); var msg = await _sender.Response(Channel).Confirm($"Starting new typing contest in **{time}**...").SendAsync();
do do
{ {
// todo fix all modifies
await Task.Delay(2000); await Task.Delay(2000);
time -= 2; time -= 2;
try { await msg.ModifyAsync(m => m.Content = $"Starting new typing contest in **{time}**.."); } try { await msg.ModifyAsync(m => m.Content = $"Starting new typing contest in **{time}**.."); }
@@ -144,13 +145,15 @@ public class TypingGame
var wpm = CurrentSentence.Length / WORD_VALUE / elapsed.TotalSeconds * 60; var wpm = CurrentSentence.Length / WORD_VALUE / elapsed.TotalSeconds * 60;
_finishedUserIds.Add(msg.Author.Id); _finishedUserIds.Add(msg.Author.Id);
var embed = new EmbedBuilder()
.WithOkColor()
.WithTitle($"{msg.Author} finished the race!")
.AddField("Place", $"#{_finishedUserIds.Count}", true)
.AddField("WPM", $"{wpm:F1} *[{elapsed.TotalSeconds:F2}sec]*", true)
.AddField("Errors", distance.ToString(), true);
await _sender.Response(Channel) await _sender.Response(Channel)
.Embed(eb => new EmbedBuilder() .Embed(embed)
.WithOkColor()
.WithTitle($"{msg.Author} finished the race!")
.AddField("Place", $"#{_finishedUserIds.Count}", true)
.AddField("WPM", $"{wpm:F1} *[{elapsed.TotalSeconds:F2}sec]*", true)
.AddField("Errors", distance.ToString(), true))
.SendAsync(); .SendAsync();
if (_finishedUserIds.Count % 4 == 0) if (_finishedUserIds.Count % 4 == 0)

View File

@@ -26,7 +26,7 @@ public class TicTacToe
private readonly IBotStrings _strings; private readonly IBotStrings _strings;
private readonly DiscordSocketClient _client; private readonly DiscordSocketClient _client;
private readonly Options _options; private readonly Options _options;
private readonly IEmbedBuilderService _eb; private readonly IMessageSenderService _sender;
public TicTacToe( public TicTacToe(
IBotStrings strings, IBotStrings strings,
@@ -34,13 +34,13 @@ public class TicTacToe
ITextChannel channel, ITextChannel channel,
IGuildUser firstUser, IGuildUser firstUser,
Options options, Options options,
IEmbedBuilderService eb) IMessageSenderService sender)
{ {
_channel = channel; _channel = channel;
_strings = strings; _strings = strings;
_client = client; _client = client;
_options = options; _options = options;
_eb = eb; _sender = sender;
_users = new[] { firstUser, null }; _users = new[] { firstUser, null };
_state = new int?[,] { { null, null, null }, { null, null, null }, { null, null, null } }; _state = new int?[,] { { null, null, null }, { null, null, null }, { null, null, null } };
@@ -115,13 +115,13 @@ public class TicTacToe
{ {
if (phase is Phase.Started or Phase.Ended) if (phase is Phase.Started or Phase.Ended)
{ {
await _channel.Response(_strings, _eb).Error(user.Mention + GetText(strs.ttt_already_running)).SendAsync(); await _sender.Response(_channel).Error(user.Mention + GetText(strs.ttt_already_running)).SendAsync();
return; return;
} }
if (_users[0] == user) if (_users[0] == user)
{ {
await _channel.Response(_strings, _eb).Error(user.Mention + GetText(strs.ttt_against_yourself)).SendAsync(); await _sender.Response(_channel).Error(user.Mention + GetText(strs.ttt_against_yourself)).SendAsync();
return; return;
} }
@@ -144,7 +144,7 @@ public class TicTacToe
var del = previousMessage?.DeleteAsync(); var del = previousMessage?.DeleteAsync();
try try
{ {
await _channel.EmbedAsync(GetEmbed(GetText(strs.ttt_time_expired))); await _sender.Response(_channel).Embed(GetEmbed(GetText(strs.ttt_time_expired))).SendAsync();
if (del is not null) if (del is not null)
await del; await del;
} }
@@ -166,7 +166,7 @@ public class TicTacToe
_client.MessageReceived += Client_MessageReceived; _client.MessageReceived += Client_MessageReceived;
previousMessage = await _channel.EmbedAsync(GetEmbed(GetText(strs.game_started))); previousMessage = await _sender.Response(_channel).Embed(GetEmbed(GetText(strs.game_started))).SendAsync();
} }
private bool IsDraw() private bool IsDraw()
@@ -259,7 +259,7 @@ public class TicTacToe
{ {
var del1 = msg.DeleteAsync(); var del1 = msg.DeleteAsync();
var del2 = previousMessage?.DeleteAsync(); var del2 = previousMessage?.DeleteAsync();
try { previousMessage = await _channel.EmbedAsync(GetEmbed(reason)); } try { previousMessage = await _sender.Response(_channel).Embed(GetEmbed(reason)).SendAsync(); }
catch { } catch { }
try { await del1; } try { await del1; }

View File

@@ -35,7 +35,7 @@ public partial class Games
return; return;
} }
game = new(Strings, _client, channel, (IGuildUser)ctx.User, options, _eb); game = new(Strings, _client, channel, (IGuildUser)ctx.User, options, _sender);
_service.TicTacToeGames.Add(channel.Id, game); _service.TicTacToeGames.Add(channel.Id, game);
await Response().Confirm(strs.ttt_created).SendAsync(); await Response().Confirm(strs.ttt_created).SendAsync();

View File

@@ -51,7 +51,7 @@ public partial class Games
if (_service.RunningTrivias.TryGetValue(ctx.Guild.Id, out var tg)) if (_service.RunningTrivias.TryGetValue(ctx.Guild.Id, out var tg))
{ {
await Response().Error(GetText(strs.trivia_already_running)).SendAsync(); await Response().Error(strs.trivia_already_running).SendAsync();
await tg.TriggerQuestionAsync(); await tg.TriggerQuestionAsync();
} }
} }

View File

@@ -376,7 +376,7 @@ public sealed class Help : NadekoModule<HelpService>
} }
var embed = _cus.GetCommandHelp(com, ctx.Guild); var embed = _cus.GetCommandHelp(com, ctx.Guild);
await channel.EmbedAsync(embed); await _sender.Response(channel).Embed(embed).SendAsync();
} }
[Cmd] [Cmd]
@@ -510,7 +510,7 @@ public sealed class Help : NadekoModule<HelpService>
private Task SelfhostAction(SocketMessageComponent smc, object _) private Task SelfhostAction(SocketMessageComponent smc, object _)
=> smc.RespondConfirmAsync(_eb, => smc.RespondConfirmAsync(_sender,
""" """
- In case you don't want or cannot Donate to NadekoBot project, but you - In case you don't want or cannot Donate to NadekoBot project, but you
- NadekoBot is a completely free and fully [open source](https://gitlab.com/kwoth/nadekobot) project which means you can run your own "selfhosted" instance on your computer or server for free. - NadekoBot is a completely free and fully [open source](https://gitlab.com/kwoth/nadekobot) project which means you can run your own "selfhosted" instance on your computer or server for free.

View File

@@ -51,10 +51,10 @@ public sealed partial class Music
} }
var embed = new EmbedBuilder() var embed = new EmbedBuilder()
.WithAuthor(GetText(strs.playlists_page(num)), MUSIC_ICON_URL) .WithAuthor(GetText(strs.playlists_page(num)), MUSIC_ICON_URL)
.WithDescription(string.Join("\n", .WithDescription(string.Join("\n",
playlists.Select(r => GetText(strs.playlists(r.Id, r.Name, r.Author, r.Songs.Count))))) playlists.Select(r => GetText(strs.playlists(r.Id, r.Name, r.Author, r.Songs.Count)))))
.WithOkColor(); .WithOkColor();
await Response().Embed(embed).SendAsync(); await Response().Embed(embed).SendAsync();
} }
@@ -111,7 +111,9 @@ public sealed partial class Music
mpl.Songs.Skip(cur * 20) mpl.Songs.Skip(cur * 20)
.Take(20) .Take(20)
.Select(x => $"`{++i}.` [{x.Title.TrimTo(45)}]({x.Query}) `{x.Provider}`")); .Select(x => $"`{++i}.` [{x.Title.TrimTo(45)}]({x.Query}) `{x.Provider}`"));
return new EmbedBuilder().WithTitle($"\"{mpl.Name}\" by {mpl.Author}").WithOkColor().WithDescription(str); return new EmbedBuilder().WithTitle($"\"{mpl.Name}\" by {mpl.Author}")
.WithOkColor()
.WithDescription(str);
}, },
mpl.Songs.Count, mpl.Songs.Count,
20); 20);
@@ -151,11 +153,13 @@ public sealed partial class Music
await uow.SaveChangesAsync(); await uow.SaveChangesAsync();
} }
await Response().Embed(new EmbedBuilder() await Response()
.WithOkColor() .Embed(new EmbedBuilder()
.WithTitle(GetText(strs.playlist_saved)) .WithOkColor()
.AddField(GetText(strs.name), name) .WithTitle(GetText(strs.playlist_saved))
.AddField(GetText(strs.id), playlist.Id.ToString())).SendAsync(); .AddField(GetText(strs.name), name)
.AddField(GetText(strs.id), playlist.Id.ToString()))
.SendAsync();
} }
[Cmd] [Cmd]
@@ -208,8 +212,9 @@ public sealed partial class Music
IUserMessage msg = null; IUserMessage msg = null;
try try
{ {
msg = await ctx.Channel.SendMessageAsync( msg = await Response()
GetText(strs.attempting_to_queue(Format.Bold(mpl.Songs.Count.ToString())))); .Pending(strs.attempting_to_queue(Format.Bold(mpl.Songs.Count.ToString())))
.SendAsync();
} }
catch (Exception) catch (Exception)
{ {

View File

@@ -15,7 +15,7 @@ public sealed class MusicService : IMusicService
private readonly IBotStrings _strings; private readonly IBotStrings _strings;
private readonly IGoogleApiService _googleApiService; private readonly IGoogleApiService _googleApiService;
private readonly YtLoader _ytLoader; private readonly YtLoader _ytLoader;
private readonly IEmbedBuilderService _eb; private readonly IMessageSenderService _sender;
private readonly ConcurrentDictionary<ulong, IMusicPlayer> _players; private readonly ConcurrentDictionary<ulong, IMusicPlayer> _players;
private readonly ConcurrentDictionary<ulong, (ITextChannel Default, ITextChannel? Override)> _outputChannels; private readonly ConcurrentDictionary<ulong, (ITextChannel Default, ITextChannel? Override)> _outputChannels;
@@ -31,7 +31,7 @@ public sealed class MusicService : IMusicService
IBotStrings strings, IBotStrings strings,
IGoogleApiService googleApiService, IGoogleApiService googleApiService,
YtLoader ytLoader, YtLoader ytLoader,
IEmbedBuilderService eb) IMessageSenderService sender)
{ {
_voiceStateService = voiceStateService; _voiceStateService = voiceStateService;
_trackResolveProvider = trackResolveProvider; _trackResolveProvider = trackResolveProvider;
@@ -42,7 +42,7 @@ public sealed class MusicService : IMusicService
_strings = strings; _strings = strings;
_googleApiService = googleApiService; _googleApiService = googleApiService;
_ytLoader = ytLoader; _ytLoader = ytLoader;
_eb = eb; _sender = sender;
_players = new(); _players = new();
_outputChannels = new ConcurrentDictionary<ulong, (ITextChannel, ITextChannel?)>(); _outputChannels = new ConcurrentDictionary<ulong, (ITextChannel, ITextChannel?)>();

View File

@@ -13,7 +13,7 @@ public sealed class CurrencyRewardService : INService, IDisposable
private readonly ICurrencyService _cs; private readonly ICurrencyService _cs;
private readonly IPatronageService _ps; private readonly IPatronageService _ps;
private readonly DbService _db; private readonly DbService _db;
private readonly IEmbedBuilderService _eb; private readonly IMessageSenderService _sender;
private readonly GamblingConfigService _config; private readonly GamblingConfigService _config;
private readonly DiscordSocketClient _client; private readonly DiscordSocketClient _client;
@@ -21,14 +21,14 @@ public sealed class CurrencyRewardService : INService, IDisposable
ICurrencyService cs, ICurrencyService cs,
IPatronageService ps, IPatronageService ps,
DbService db, DbService db,
IEmbedBuilderService eb, IMessageSenderService sender,
GamblingConfigService config, GamblingConfigService config,
DiscordSocketClient client) DiscordSocketClient client)
{ {
_cs = cs; _cs = cs;
_ps = ps; _ps = ps;
_db = db; _db = db;
_eb = eb; _sender = sender;
_config = config; _config = config;
_client = client; _client = client;
@@ -175,7 +175,7 @@ public sealed class CurrencyRewardService : INService, IDisposable
.WithOkColor() .WithOkColor()
.WithDescription(message); .WithDescription(message);
await user.EmbedAsync(eb); await _sender.Response(user).Embed(eb).SendAsync();
} }
catch catch
{ {

View File

@@ -31,10 +31,12 @@ public partial class Patronage : NadekoModule
_ = ctx.Channel.TriggerTypingAsync(); _ = ctx.Channel.TriggerTypingAsync();
var result = await _service.SendMessageToPatronsAsync(tierAndHigher, message); var result = await _service.SendMessageToPatronsAsync(tierAndHigher, message);
await Response().Confirm(strs.patron_msg_sent( await Response()
Format.Code(tierAndHigher.ToString()), .Confirm(strs.patron_msg_sent(
Format.Bold(result.Success.ToString()), Format.Code(tierAndHigher.ToString()),
Format.Bold(result.Failed.ToString()))).SendAsync(); Format.Bold(result.Success.ToString()),
Format.Bold(result.Failed.ToString())))
.SendAsync();
} }
// [OwnerOnly] // [OwnerOnly]
@@ -69,9 +71,9 @@ public partial class Patronage : NadekoModule
var quotaStats = await _service.GetUserQuotaStatistic(user.Id); var quotaStats = await _service.GetUserQuotaStatistic(user.Id);
var eb = new EmbedBuilder() var eb = new EmbedBuilder()
.WithAuthor(user) .WithAuthor(user)
.WithTitle(GetText(strs.patron_info)) .WithTitle(GetText(strs.patron_info))
.WithOkColor(); .WithOkColor();
if (quotaStats.Commands.Count == 0 if (quotaStats.Commands.Count == 0
&& quotaStats.Groups.Count == 0 && quotaStats.Groups.Count == 0
@@ -82,7 +84,7 @@ public partial class Patronage : NadekoModule
else else
{ {
eb.AddField(GetText(strs.tier), Format.Bold(patron.Tier.ToFullName()), true) eb.AddField(GetText(strs.tier), Format.Bold(patron.Tier.ToFullName()), true)
.AddField(GetText(strs.pledge), $"**{patron.Amount / 100.0f:N1}$**", true); .AddField(GetText(strs.pledge), $"**{patron.Amount / 100.0f:N1}$**", true);
if (patron.Tier != PatronTier.None) if (patron.Tier != PatronTier.None)
eb.AddField(GetText(strs.expires), patron.ValidThru.AddDays(1).ToShortAndRelativeTimestampTag(), true); eb.AddField(GetText(strs.expires), patron.ValidThru.AddDays(1).ToShortAndRelativeTimestampTag(), true);
@@ -114,7 +116,7 @@ public partial class Patronage : NadekoModule
try try
{ {
await ctx.User.EmbedAsync(eb); await Response().User(ctx.User).Embed(eb).SendAsync();
_ = ctx.OkAsync(); _ = ctx.OkAsync();
} }
catch catch

View File

@@ -29,7 +29,6 @@ public sealed class PatronageService
private readonly DbService _db; private readonly DbService _db;
private readonly DiscordSocketClient _client; private readonly DiscordSocketClient _client;
private readonly ISubscriptionHandler _subsHandler; private readonly ISubscriptionHandler _subsHandler;
private readonly IEmbedBuilderService _eb;
private static readonly TypedKey<long> _quotaKey private static readonly TypedKey<long> _quotaKey
= new($"quota:last_hourly_reset"); = new($"quota:last_hourly_reset");
@@ -43,7 +42,6 @@ public sealed class PatronageService
DbService db, DbService db,
DiscordSocketClient client, DiscordSocketClient client,
ISubscriptionHandler subsHandler, ISubscriptionHandler subsHandler,
IEmbedBuilderService eb,
IBotCache cache, IBotCache cache,
IBotCredsProvider creds, IBotCredsProvider creds,
IMessageSenderService sender) IMessageSenderService sender)
@@ -52,10 +50,9 @@ public sealed class PatronageService
_db = db; _db = db;
_client = client; _client = client;
_subsHandler = subsHandler; _subsHandler = subsHandler;
_eb = eb; _sender = sender;
_cache = cache; _cache = cache;
_creds = creds; _creds = creds;
_sender = sender;
} }
public Task OnReadyAsync() public Task OnReadyAsync()
@@ -310,12 +307,12 @@ public sealed class PatronageService
ins => ins =>
{ {
var eb = new EmbedBuilder() var eb = new EmbedBuilder()
.WithPendingColor() .WithPendingColor()
.WithTitle("Insufficient Patron Tier") .WithTitle("Insufficient Patron Tier")
.AddField("For", $"{ins.FeatureType}: `{ins.Feature}`", true) .AddField("For", $"{ins.FeatureType}: `{ins.Feature}`", true)
.AddField("Required Tier", .AddField("Required Tier",
$"[{ins.RequiredTier.ToFullName()}](https://patreon.com/join/nadekobot)", $"[{ins.RequiredTier.ToFullName()}](https://patreon.com/join/nadekobot)",
true); true);
if (ctx.Guild is null || ctx.Guild?.OwnerId == ctx.User.Id) if (ctx.Guild is null || ctx.Guild?.OwnerId == ctx.User.Id)
eb.WithDescription("You don't have the sufficent Patron Tier to run this command.") eb.WithDescription("You don't have the sufficent Patron Tier to run this command.")
@@ -333,15 +330,15 @@ public sealed class PatronageService
.Embed(eb) .Embed(eb)
.SendAsync(); .SendAsync();
else else
_ = ctx.User.EmbedAsync(eb); _ = _sender.Response(ctx).User(ctx.User).Embed(eb).SendAsync();
return true; return true;
}, },
quota => quota =>
{ {
var eb = new EmbedBuilder() var eb = new EmbedBuilder()
.WithPendingColor() .WithPendingColor()
.WithTitle("Quota Limit Reached"); .WithTitle("Quota Limit Reached");
if (quota.IsOwnQuota || ctx.User.Id == ownerId) if (quota.IsOwnQuota || ctx.User.Id == ownerId)
{ {
@@ -369,7 +366,7 @@ public sealed class PatronageService
.Embed(eb) .Embed(eb)
.SendAsync(); .SendAsync();
else else
_ = ctx.User.EmbedAsync(eb); _ = _sender.Response(ctx).User(ctx.User).Embed(eb).SendAsync();
return true; return true;
}); });
@@ -782,30 +779,30 @@ public sealed class PatronageService
return; return;
var eb = new EmbedBuilder() var eb = new EmbedBuilder()
.WithOkColor() .WithOkColor()
.WithTitle("❤️ Thank you for supporting NadekoBot! ❤️") .WithTitle("❤️ Thank you for supporting NadekoBot! ❤️")
.WithDescription( .WithDescription(
"Your donation has been processed and you will receive the rewards shortly.\n" "Your donation has been processed and you will receive the rewards shortly.\n"
+ "You can visit <https://www.patreon.com/join/nadekobot> to see rewards for your tier. 🎉") + "You can visit <https://www.patreon.com/join/nadekobot> to see rewards for your tier. 🎉")
.AddField("Tier", Format.Bold(patron.Tier.ToString()), true) .AddField("Tier", Format.Bold(patron.Tier.ToString()), true)
.AddField("Pledge", $"**{patron.Amount / 100.0f:N1}$**", true) .AddField("Pledge", $"**{patron.Amount / 100.0f:N1}$**", true)
.AddField("Expires", .AddField("Expires",
patron.ValidThru.AddDays(1).ToShortAndRelativeTimestampTag(), patron.ValidThru.AddDays(1).ToShortAndRelativeTimestampTag(),
true) true)
.AddField("Instructions", .AddField("Instructions",
""" """
*- Within the next **1-2 minutes** you will have all of the benefits of the Tier you've subscribed to.* *- Within the next **1-2 minutes** you will have all of the benefits of the Tier you've subscribed to.*
*- You can check your benefits on <https://www.patreon.com/join/nadekobot>* *- You can check your benefits on <https://www.patreon.com/join/nadekobot>*
*- You can use the `.patron` command in this chat to check your current quota usage for the Patron-only commands* *- You can use the `.patron` command in this chat to check your current quota usage for the Patron-only commands*
*- **ALL** of the servers that you **own** will enjoy your Patron benefits.* *- **ALL** of the servers that you **own** will enjoy your Patron benefits.*
*- You can use any of the commands available in your tier on any server (assuming you have sufficient permissions to run those commands)* *- You can use any of the commands available in your tier on any server (assuming you have sufficient permissions to run those commands)*
*- Any user in any of your servers can use Patron-only commands, but they will spend **your quota**, which is why it's recommended to use Nadeko's command cooldown system (.h .cmdcd) or permission system to limit the command usage for your server members.* *- Any user in any of your servers can use Patron-only commands, but they will spend **your quota**, which is why it's recommended to use Nadeko's command cooldown system (.h .cmdcd) or permission system to limit the command usage for your server members.*
*- Permission guide can be found here if you're not familiar with it: <https://nadekobot.readthedocs.io/en/latest/permissions-system/>* *- Permission guide can be found here if you're not familiar with it: <https://nadekobot.readthedocs.io/en/latest/permissions-system/>*
""", """,
inline: false) inline: false)
.WithFooter($"platform id: {patron.UniquePlatformUserId}"); .WithFooter($"platform id: {patron.UniquePlatformUserId}");
await user.EmbedAsync(eb); await _sender.Response(user).Embed(eb).SendAsync();
} }
catch catch
{ {
@@ -830,7 +827,7 @@ public sealed class PatronageService
try try
{ {
var user = await _client.GetUserAsync(patron.UserId); var user = await _client.GetUserAsync(patron.UserId);
await user.SendAsync(text); await _sender.Response(user).Text(text).SendAsync();
++succ; ++succ;
} }
catch catch

View File

@@ -17,7 +17,6 @@ public class PermissionService : IExecPreCommand, INService
private readonly DbService _db; private readonly DbService _db;
private readonly CommandHandler _cmd; private readonly CommandHandler _cmd;
private readonly IBotStrings _strings; private readonly IBotStrings _strings;
private readonly IEmbedBuilderService _eb;
private readonly IMessageSenderService _sender; private readonly IMessageSenderService _sender;
public PermissionService( public PermissionService(
@@ -25,13 +24,11 @@ public class PermissionService : IExecPreCommand, INService
DbService db, DbService db,
CommandHandler cmd, CommandHandler cmd,
IBotStrings strings, IBotStrings strings,
IEmbedBuilderService eb,
IMessageSenderService sender) IMessageSenderService sender)
{ {
_db = db; _db = db;
_cmd = cmd; _cmd = cmd;
_strings = strings; _strings = strings;
_eb = eb;
_sender = sender; _sender = sender;
using var uow = _db.GetDbContext(); using var uow = _db.GetDbContext();

View File

@@ -6,7 +6,6 @@ using System.Text.Json;
namespace NadekoBot.Modules.Searches; namespace NadekoBot.Modules.Searches;
// todo fix stock
public sealed class DefaultStockDataService : IStockDataService, INService public sealed class DefaultStockDataService : IStockDataService, INService
{ {
private readonly IHttpClientFactory _httpClientFactory; private readonly IHttpClientFactory _httpClientFactory;

View File

@@ -14,7 +14,7 @@ public class FeedsService : INService
private readonly DbService _db; private readonly DbService _db;
private readonly ConcurrentDictionary<string, List<FeedSub>> _subs; private readonly ConcurrentDictionary<string, List<FeedSub>> _subs;
private readonly DiscordSocketClient _client; private readonly DiscordSocketClient _client;
private readonly IEmbedBuilderService _eb; private readonly IMessageSenderService _sender;
private readonly ConcurrentDictionary<string, DateTime> _lastPosts = new(); private readonly ConcurrentDictionary<string, DateTime> _lastPosts = new();
private readonly Dictionary<string, uint> _errorCounters = new(); private readonly Dictionary<string, uint> _errorCounters = new();
@@ -23,7 +23,7 @@ public class FeedsService : INService
IBot bot, IBot bot,
DbService db, DbService db,
DiscordSocketClient client, DiscordSocketClient client,
IEmbedBuilderService eb) IMessageSenderService sender)
{ {
_db = db; _db = db;
@@ -42,7 +42,7 @@ public class FeedsService : INService
} }
_client = client; _client = client;
_eb = eb; _sender = sender;
_ = Task.Run(TrackFeeds); _ = Task.Run(TrackFeeds);
} }

View File

@@ -69,7 +69,7 @@ public partial class Searches
} }
memeUrl += ".png"; memeUrl += ".png";
await ctx.Channel.SendMessageAsync(memeUrl); await Response().Text(memeUrl).SendAsync();
} }
private static string Replace(string input) private static string Replace(string input)

View File

@@ -165,7 +165,7 @@ public partial class Searches
} }
await AddYoutubeUrlToCacheAsync(query, result.Url); await AddYoutubeUrlToCacheAsync(query, result.Url);
await ctx.Channel.SendMessageAsync(result.Url); await Response().Text(result.Url).SendAsync();
} }
// [Cmd] // [Cmd]

View File

@@ -141,7 +141,7 @@ public partial class Searches : NadekoModule<SearchesService>
.AddField(GetText(strs.location), string.Join('\n', data.Address.Split(", ")), true) .AddField(GetText(strs.location), string.Join('\n', data.Address.Split(", ")), true)
.AddField(GetText(strs.timezone), data.TimeZoneName, true); .AddField(GetText(strs.timezone), data.TimeZoneName, true);
await ctx.Channel.SendMessageAsync(embed: eb.Build()); await Response().Embed(eb).SendAsync();
} }
[Cmd] [Cmd]
@@ -441,7 +441,7 @@ public partial class Searches : NadekoModule<SearchesService>
if (data.Query.Pages[0].Missing || string.IsNullOrWhiteSpace(data.Query.Pages[0].FullUrl)) if (data.Query.Pages[0].Missing || string.IsNullOrWhiteSpace(data.Query.Pages[0].FullUrl))
await Response().Error(strs.wiki_page_not_found).SendAsync(); await Response().Error(strs.wiki_page_not_found).SendAsync();
else else
await ctx.Channel.SendMessageAsync(data.Query.Pages[0].FullUrl); await Response().Text(data.Query.Pages[0].FullUrl).SendAsync();
} }
[Cmd] [Cmd]
@@ -514,7 +514,7 @@ public partial class Searches : NadekoModule<SearchesService>
var url = Uri.EscapeDataString($"https://{target}.fandom.com/wiki/{title}"); var url = Uri.EscapeDataString($"https://{target}.fandom.com/wiki/{title}");
var response = $@"`{GetText(strs.title)}` {title.SanitizeMentions()} var response = $@"`{GetText(strs.title)}` {title.SanitizeMentions()}
`{GetText(strs.url)}:` {url}"; `{GetText(strs.url)}:` {url}";
await ctx.Channel.SendMessageAsync(response); await Response().Text(response).SendAsync();
} }
catch catch
{ {
@@ -575,7 +575,7 @@ public partial class Searches : NadekoModule<SearchesService>
// .AddField(GetText(strs.price), gameData.IsFree ? GetText(strs.FREE) : game, true) // .AddField(GetText(strs.price), gameData.IsFree ? GetText(strs.FREE) : game, true)
// .AddField(GetText(strs.links), gameData.GetGenresString(), true) // .AddField(GetText(strs.links), gameData.GetGenresString(), true)
// .WithFooter(GetText(strs.recommendations(gameData.TotalRecommendations))); // .WithFooter(GetText(strs.recommendations(gameData.TotalRecommendations)));
await ctx.Channel.SendMessageAsync($"https://store.steampowered.com/app/{appId}"); await Response().Text($"https://store.steampowered.com/app/{appId}").SendAsync();
} }
private async Task<bool> ValidateQuery([MaybeNullWhen(false)] string query) private async Task<bool> ValidateQuery([MaybeNullWhen(false)] string query)

View File

@@ -25,7 +25,7 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
private readonly ConcurrentHashSet<ulong> _deleteOnOfflineServers; private readonly ConcurrentHashSet<ulong> _deleteOnOfflineServers;
private readonly IPubSub _pubSub; private readonly IPubSub _pubSub;
private readonly IEmbedBuilderService _eb; private readonly IMessageSenderService _sender;
private readonly SearchesConfigService _config; private readonly SearchesConfigService _config;
private readonly IReplacementService _repSvc; private readonly IReplacementService _repSvc;
@@ -49,7 +49,7 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
IHttpClientFactory httpFactory, IHttpClientFactory httpFactory,
IBot bot, IBot bot,
IPubSub pubSub, IPubSub pubSub,
IEmbedBuilderService eb, IMessageSenderService sender,
SearchesConfigService config, SearchesConfigService config,
IReplacementService repSvc) IReplacementService repSvc)
{ {
@@ -57,7 +57,7 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
_client = client; _client = client;
_strings = strings; _strings = strings;
_pubSub = pubSub; _pubSub = pubSub;
_eb = eb; _sender = sender;
_config = config; _config = config;
_repSvc = repSvc; _repSvc = repSvc;
@@ -285,7 +285,10 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
? "" ? ""
: await _repSvc.ReplaceAsync(fs.Message, repCtx); : await _repSvc.ReplaceAsync(fs.Message, repCtx);
var msg = await textChannel.EmbedAsync(GetEmbed(fs.GuildId, stream, false), message); var msg = await _sender.Response(textChannel)
.Embed(GetEmbed(fs.GuildId, stream, false))
.Text(message)
.SendAsync();
// only cache the ids of channel/message pairs // only cache the ids of channel/message pairs
if (_deleteOnOfflineServers.Contains(fs.GuildId)) if (_deleteOnOfflineServers.Contains(fs.GuildId))

View File

@@ -12,7 +12,7 @@ public sealed class TranslateService : ITranslateService, IExecNoCommand, IReady
{ {
private readonly IGoogleApiService _google; private readonly IGoogleApiService _google;
private readonly DbService _db; private readonly DbService _db;
private readonly IEmbedBuilderService _eb; private readonly IMessageSenderService _sender;
private readonly IBot _bot; private readonly IBot _bot;
private readonly ConcurrentDictionary<ulong, bool> _atcs = new(); private readonly ConcurrentDictionary<ulong, bool> _atcs = new();
@@ -21,12 +21,12 @@ public sealed class TranslateService : ITranslateService, IExecNoCommand, IReady
public TranslateService( public TranslateService(
IGoogleApiService google, IGoogleApiService google,
DbService db, DbService db,
IEmbedBuilderService eb, IMessageSenderService sender,
IBot bot) IBot bot)
{ {
_google = google; _google = google;
_db = db; _db = db;
_eb = eb; _sender = sender;
_bot = bot; _bot = bot;
} }
@@ -77,7 +77,7 @@ public sealed class TranslateService : ITranslateService, IExecNoCommand, IReady
.AddField(langs.From, um.Content) .AddField(langs.From, um.Content)
.AddField(langs.To, output); .AddField(langs.To, output);
await tch.EmbedAsync(embed); await _sender.Response(tch).Embed(embed).SendAsync();
try try
{ {

View File

@@ -13,7 +13,7 @@ public sealed class GiveawayService : INService, IReadyExecutor
private readonly DbService _db; private readonly DbService _db;
private readonly IBotCredentials _creds; private readonly IBotCredentials _creds;
private readonly DiscordSocketClient _client; private readonly DiscordSocketClient _client;
private readonly IEmbedBuilderService _eb; private readonly IMessageSenderService _sender;
private readonly IBotStrings _strings; private readonly IBotStrings _strings;
private readonly ILocalization _localization; private readonly ILocalization _localization;
private readonly IMemoryCache _cache; private readonly IMemoryCache _cache;
@@ -22,12 +22,12 @@ public sealed class GiveawayService : INService, IReadyExecutor
private readonly ConcurrentDictionary<int, GiveawayRerollData> _rerolls = new(); private readonly ConcurrentDictionary<int, GiveawayRerollData> _rerolls = new();
public GiveawayService(DbService db, IBotCredentials creds, DiscordSocketClient client, public GiveawayService(DbService db, IBotCredentials creds, DiscordSocketClient client,
IEmbedBuilderService eb, IBotStrings strings, ILocalization localization, IMemoryCache cache) IMessageSenderService sender, IBotStrings strings, ILocalization localization, IMemoryCache cache)
{ {
_db = db; _db = db;
_creds = creds; _creds = creds;
_client = client; _client = client;
_eb = eb; _sender = sender;
_strings = strings; _strings = strings;
_localization = localization; _localization = localization;
_cache = cache; _cache = cache;
@@ -317,8 +317,7 @@ public sealed class GiveawayService : INService, IReadyExecutor
{Format.Code(winner.UserId.ToString())} {Format.Code(winner.UserId.ToString())}
"""; """;
var eb = _eb var eb = new EmbedBuilder()
.Create()
.WithOkColor() .WithOkColor()
.WithTitle(GetText(strs.giveaway_ended)) .WithTitle(GetText(strs.giveaway_ended))
.WithDescription(ga.Message) .WithDescription(ga.Message)
@@ -334,7 +333,7 @@ public sealed class GiveawayService : INService, IReadyExecutor
catch catch
{ {
_ = msg.DeleteAsync(); _ = msg.DeleteAsync();
await ch.EmbedAsync(eb); await _sender.Response(ch).Embed(eb).SendAsync();
} }
} }

View File

@@ -133,23 +133,23 @@ public partial class Utility
private async Task ShowQuoteData(Quote data) private async Task ShowQuoteData(Quote data)
{ {
var eb = new EmbedBuilder() var eb = new EmbedBuilder()
.WithOkColor() .WithOkColor()
.WithTitle($"{GetText(strs.quote_id($"#{data.Id}"))} | {GetText(strs.response)}:") .WithTitle($"{GetText(strs.quote_id($"#{data.Id}"))} | {GetText(strs.response)}:")
.WithDescription(Format.Sanitize(data.Text).Replace("](", "]\\(").TrimTo(4096)) .WithDescription(Format.Sanitize(data.Text).Replace("](", "]\\(").TrimTo(4096))
.AddField(GetText(strs.trigger), data.Keyword) .AddField(GetText(strs.trigger), data.Keyword)
.WithFooter( .WithFooter(
GetText(strs.created_by($"{data.AuthorName} ({data.AuthorId})"))) GetText(strs.created_by($"{data.AuthorName} ({data.AuthorId})")));
.Build();
if (!(data.Text.Length > 4096)) if (!(data.Text.Length > 4096))
{ {
await ctx.Channel.SendMessageAsync(embed: eb); await Response().Embed(eb).SendAsync();
return; return;
} }
// todo all send files should go through response system too
await ctx.Channel.SendFileAsync( await ctx.Channel.SendFileAsync(
attachment: new FileAttachment(await data.Text.ToStream(), "quote.txt"), attachment: new FileAttachment(await data.Text.ToStream(), "quote.txt"),
embed: eb); embed: eb.Build());
} }
private async Task QuoteSearchinternalAsync(string? keyword, string textOrAuthor) private async Task QuoteSearchinternalAsync(string? keyword, string textOrAuthor)
@@ -168,10 +168,12 @@ public partial class Utility
if (quote is null) if (quote is null)
return; return;
await ctx.Channel.SendMessageAsync($"`#{quote.Id}` 💬 " await Response()
+ quote.Keyword.ToLowerInvariant() .Confirm($"`#{quote.Id}` 💬 ",
+ ": " quote.Keyword.ToLowerInvariant()
+ quote.Text.SanitizeAllMentions()); + ": "
+ quote.Text.SanitizeAllMentions())
.SendAsync();
} }
[Cmd] [Cmd]
@@ -204,7 +206,7 @@ public partial class Utility
if (quote is null || quote.GuildId != ctx.Guild.Id) if (quote is null || quote.GuildId != ctx.Guild.Id)
{ {
await Response().Error(GetText(strs.quotes_notfound)).SendAsync(); await Response().Error(strs.quotes_notfound).SendAsync();
return; return;
} }

View File

@@ -11,25 +11,26 @@ namespace NadekoBot.Modules.Utility.Services;
public class RemindService : INService, IReadyExecutor, IRemindService public class RemindService : INService, IReadyExecutor, IRemindService
{ {
private readonly Regex _regex = private readonly Regex _regex =
new(@"^(?:(?:at|on(?:\sthe)?)?\s*(?<date>(?:\d{2}:\d{2}\s)?\d{1,2}\.\d{1,2}(?:\.\d{2,4})?)|(?:in\s?)?\s*(?:(?<mo>\d+)(?:\s?(?:months?|mos?),?))?(?:(?:\sand\s|\s*)?(?<w>\d+)(?:\s?(?:weeks?|w),?))?(?:(?:\sand\s|\s*)?(?<d>\d+)(?:\s?(?:days?|d),?))?(?:(?:\sand\s|\s*)?(?<h>\d+)(?:\s?(?:hours?|h),?))?(?:(?:\sand\s|\s*)?(?<m>\d+)(?:\s?(?:minutes?|mins?|m),?))?)\s+(?:to:?\s+)?(?<what>(?:\r\n|[\r\n]|.)+)", new(
@"^(?:(?:at|on(?:\sthe)?)?\s*(?<date>(?:\d{2}:\d{2}\s)?\d{1,2}\.\d{1,2}(?:\.\d{2,4})?)|(?:in\s?)?\s*(?:(?<mo>\d+)(?:\s?(?:months?|mos?),?))?(?:(?:\sand\s|\s*)?(?<w>\d+)(?:\s?(?:weeks?|w),?))?(?:(?:\sand\s|\s*)?(?<d>\d+)(?:\s?(?:days?|d),?))?(?:(?:\sand\s|\s*)?(?<h>\d+)(?:\s?(?:hours?|h),?))?(?:(?:\sand\s|\s*)?(?<m>\d+)(?:\s?(?:minutes?|mins?|m),?))?)\s+(?:to:?\s+)?(?<what>(?:\r\n|[\r\n]|.)+)",
RegexOptions.Compiled | RegexOptions.Multiline); RegexOptions.Compiled | RegexOptions.Multiline);
private readonly DiscordSocketClient _client; private readonly DiscordSocketClient _client;
private readonly DbService _db; private readonly DbService _db;
private readonly IBotCredentials _creds; private readonly IBotCredentials _creds;
private readonly IEmbedBuilderService _eb; private readonly IMessageSenderService _sender;
private readonly CultureInfo _culture; private readonly CultureInfo _culture;
public RemindService( public RemindService(
DiscordSocketClient client, DiscordSocketClient client,
DbService db, DbService db,
IBotCredentials creds, IBotCredentials creds,
IEmbedBuilderService eb) IMessageSenderService sender)
{ {
_client = client; _client = client;
_db = db; _db = db;
_creds = creds; _creds = creds;
_eb = eb; _sender = sender;
try try
{ {
@@ -162,6 +163,7 @@ public class RemindService : INService, IReadyExecutor, IRemindService
values[groupName] = value; values[groupName] = value;
} }
ts = new TimeSpan((30 * values["mo"]) + (7 * values["w"]) + values["d"], values["h"], values["m"], 0); ts = new TimeSpan((30 * values["mo"]) + (7 * values["w"]) + values["d"], values["h"], values["m"], 0);
} }
@@ -197,22 +199,24 @@ public class RemindService : INService, IReadyExecutor, IRemindService
if (st is SmartEmbedText set) if (st is SmartEmbedText set)
{ {
await ch.SendMessageAsync(null, embed: set.GetEmbed().Build()); await _sender.Response(ch).Embed(set.GetEmbed()).SendAsync();
} }
else if (st is SmartEmbedTextArray seta) else if (st is SmartEmbedTextArray seta)
{ {
await ch.SendMessageAsync(null, embeds: seta.GetEmbedBuilders().Map(x => x.Build())); await _sender.Response(ch).Embeds(seta.GetEmbedBuilders()).SendAsync();
} }
else else
{ {
await ch.EmbedAsync(new EmbedBuilder() await _sender.Response(ch)
.WithOkColor() .Embed(new EmbedBuilder()
.WithTitle("Reminder") .WithOkColor()
.AddField("Created At", .WithTitle("Reminder")
r.DateAdded.HasValue ? r.DateAdded.Value.ToLongDateString() : "?") .AddField("Created At",
.AddField("By", r.DateAdded.HasValue ? r.DateAdded.Value.ToLongDateString() : "?")
(await ch.GetUserAsync(r.UserId))?.ToString() ?? r.UserId.ToString()), .AddField("By",
r.Message); (await ch.GetUserAsync(r.UserId))?.ToString() ?? r.UserId.ToString()))
.Text(r.Message)
.SendAsync();
} }
} }
catch (Exception ex) catch (Exception ex)
@@ -227,7 +231,8 @@ public class RemindService : INService, IReadyExecutor, IRemindService
public TimeSpan Time { get; set; } public TimeSpan Time { get; set; }
} }
public async Task AddReminderAsync(ulong userId, public async Task AddReminderAsync(
ulong userId,
ulong targetId, ulong targetId,
ulong? guildId, ulong? guildId,
bool isPrivate, bool isPrivate,

View File

@@ -1,4 +1,5 @@
using NadekoBot.Db.Models; using NadekoBot.Db.Models;
using System.Text;
namespace NadekoBot.Modules.Utility; namespace NadekoBot.Modules.Utility;
@@ -86,8 +87,8 @@ public partial class Utility
(curPage) => (curPage) =>
{ {
var eb = new EmbedBuilder() var eb = new EmbedBuilder()
.WithOkColor() .WithOkColor()
.WithTitle(GetText(strs.todo_list)); .WithTitle(GetText(strs.todo_list));
ShowTodoItem(todos, curPage, eb); ShowTodoItem(todos, curPage, eb);
@@ -99,15 +100,15 @@ public partial class Utility
private static void ShowTodoItem(IReadOnlyCollection<TodoModel> todos, int curPage, EmbedBuilder eb) private static void ShowTodoItem(IReadOnlyCollection<TodoModel> todos, int curPage, EmbedBuilder eb)
{ {
var sb = new StringBuilder();
foreach (var todo in todos.Skip(curPage * 9).Take(9)) foreach (var todo in todos.Skip(curPage * 9).Take(9))
{ {
// green circle and yellow circle emojis sb.AppendLine($"{(todo.IsDone ? "" : "")} {Format.Code(new kwum(todo.Id).ToString())} {todo.Todo}");
eb.AddField($"-",
$"{(todo.IsDone sb.AppendLine("---");
? ""
: "🟡")} {Format.Code(new kwum(todo.Id).ToString())} {todo.Todo}",
false);
} }
eb.WithDescription(sb.ToString());
} }
[Group("archive")] [Group("archive")]
@@ -150,8 +151,8 @@ public partial class Utility
(curPage) => (curPage) =>
{ {
var eb = new EmbedBuilder() var eb = new EmbedBuilder()
.WithTitle(GetText(strs.todo_archive_list)) .WithTitle(GetText(strs.todo_archive_list))
.WithOkColor(); .WithOkColor();
foreach (var archivedList in archivedTodoLists.Skip(curPage * 9).Take(9)) foreach (var archivedList in archivedTodoLists.Skip(curPage * 9).Take(9))
{ {
@@ -179,8 +180,8 @@ public partial class Utility
(curPage) => (curPage) =>
{ {
var eb = new EmbedBuilder() var eb = new EmbedBuilder()
.WithOkColor() .WithOkColor()
.WithTitle(GetText(strs.todo_list)); .WithTitle(GetText(strs.todo_list));
ShowTodoItem(list.Items, curPage, eb); ShowTodoItem(list.Items, curPage, eb);

View File

@@ -90,10 +90,10 @@ public partial class Utility
res = Math.Round(res, 4); res = Math.Round(res, 4);
await Response() await Response()
.Confirm(GetText(strs.convert(value, .Confirm(strs.convert(value,
originUnit.Triggers.Last(), originUnit.Triggers.Last(),
res, res,
targetUnit.Triggers.Last()))) targetUnit.Triggers.Last()))
.SendAsync(); .SendAsync();
} }
} }

View File

@@ -337,7 +337,7 @@ public partial class Utility : NadekoModule
if (string.IsNullOrWhiteSpace(result)) if (string.IsNullOrWhiteSpace(result))
await Response().Error(strs.showemojis_none).SendAsync(); await Response().Error(strs.showemojis_none).SendAsync();
else else
await ctx.Channel.SendMessageAsync(result.TrimTo(2000)); await Response().Text(result.TrimTo(2000)).SendAsync();
} }
[Cmd] [Cmd]
@@ -613,7 +613,7 @@ public partial class Utility : NadekoModule
try try
{ {
var sw = Stopwatch.StartNew(); var sw = Stopwatch.StartNew();
var msg = await ctx.Channel.SendMessageAsync("🏓"); var msg = await Response().Text("🏓").SendAsync();
sw.Stop(); sw.Stop();
msg.DeleteAfter(0); msg.DeleteAfter(0);

View File

@@ -9,16 +9,19 @@ public class VerboseErrorsService : INService
private readonly DbService _db; private readonly DbService _db;
private readonly CommandHandler _ch; private readonly CommandHandler _ch;
private readonly ICommandsUtilityService _hs; private readonly ICommandsUtilityService _hs;
private readonly IMessageSenderService _sender;
public VerboseErrorsService( public VerboseErrorsService(
IBot bot, IBot bot,
DbService db, DbService db,
CommandHandler ch, CommandHandler ch,
IMessageSenderService sender,
ICommandsUtilityService hs) ICommandsUtilityService hs)
{ {
_db = db; _db = db;
_ch = ch; _ch = ch;
_hs = hs; _hs = hs;
_sender = sender;
_ch.CommandErrored += LogVerboseError; _ch.CommandErrored += LogVerboseError;
@@ -38,7 +41,7 @@ public class VerboseErrorsService : INService
.WithFooter("Admin may disable verbose errors via `.ve` command") .WithFooter("Admin may disable verbose errors via `.ve` command")
.WithErrorColor(); .WithErrorColor();
await channel.EmbedAsync(embed); await _sender.Response(channel).Embed(embed).SendAsync();
} }
catch catch
{ {

View File

@@ -31,7 +31,6 @@ public class XpService : INService, IReadyExecutor, IExecNoCommand
private readonly IHttpClientFactory _httpFactory; private readonly IHttpClientFactory _httpFactory;
private readonly XpConfigService _xpConfig; private readonly XpConfigService _xpConfig;
private readonly IPubSub _pubSub; private readonly IPubSub _pubSub;
private readonly IEmbedBuilderService _eb;
private readonly ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>> _excludedRoles; private readonly ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>> _excludedRoles;
private readonly ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>> _excludedChannels; private readonly ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>> _excludedChannels;
@@ -62,7 +61,6 @@ public class XpService : INService, IReadyExecutor, IExecNoCommand
IHttpClientFactory http, IHttpClientFactory http,
XpConfigService xpConfig, XpConfigService xpConfig,
IPubSub pubSub, IPubSub pubSub,
IEmbedBuilderService eb,
IPatronageService ps, IPatronageService ps,
IMessageSenderService sender) IMessageSenderService sender)
{ {
@@ -75,14 +73,13 @@ public class XpService : INService, IReadyExecutor, IExecNoCommand
_httpFactory = http; _httpFactory = http;
_xpConfig = xpConfig; _xpConfig = xpConfig;
_pubSub = pubSub; _pubSub = pubSub;
_eb = eb; _sender = sender;
_excludedServers = new(); _excludedServers = new();
_excludedChannels = new(); _excludedChannels = new();
_client = client; _client = client;
_xpTemplateReloadKey = new("xp.template.reload"); _xpTemplateReloadKey = new("xp.template.reload");
_ps = ps; _ps = ps;
_c = c; _c = c;
_sender = sender;
InternalReloadXpTemplate(); InternalReloadXpTemplate();
@@ -393,11 +390,12 @@ public class XpService : INService, IReadyExecutor, IExecNoCommand
{ {
if (notifyLoc == XpNotificationLocation.Dm) if (notifyLoc == XpNotificationLocation.Dm)
{ {
await user.SendConfirmAsync(_eb, await _sender.Response(user)
_strings.GetText(strs.level_up_dm(user.Mention, .Confirm(_strings.GetText(strs.level_up_dm(user.Mention,
Format.Bold(newLevel.ToString()), Format.Bold(newLevel.ToString()),
Format.Bold(guild.ToString() ?? "-")), Format.Bold(guild.ToString() ?? "-")),
guild.Id)); guild.Id))
.SendAsync();
} }
else // channel else // channel
{ {

View File

@@ -8,20 +8,20 @@ public sealed class PermissionChecker : IPermissionChecker, INService
private readonly PermissionService _perms; private readonly PermissionService _perms;
private readonly GlobalPermissionService _gperm; private readonly GlobalPermissionService _gperm;
private readonly CmdCdService _cmdCds; private readonly CmdCdService _cmdCds;
private readonly IEmbedBuilderService _ebs; private readonly IMessageSenderService _sender;
private readonly CommandHandler _ch; private readonly CommandHandler _ch;
public PermissionChecker( public PermissionChecker(
PermissionService perms, PermissionService perms,
GlobalPermissionService gperm, GlobalPermissionService gperm,
CmdCdService cmdCds, CmdCdService cmdCds,
IEmbedBuilderService ebs, IMessageSenderService sender,
CommandHandler ch) CommandHandler ch)
{ {
_perms = perms; _perms = perms;
_gperm = gperm; _gperm = gperm;
_cmdCds = cmdCds; _cmdCds = cmdCds;
_ebs = ebs; _sender = sender;
_ch = ch; _ch = ch;
} }

View File

@@ -26,7 +26,6 @@ public enum LogType
ChannelUpdated, ChannelUpdated,
UserPresence, UserPresence,
VoicePresence, VoicePresence,
VoicePresenceTts,
UserMuted, UserMuted,
UserWarned, UserWarned,

View File

@@ -12,7 +12,6 @@ public sealed class DmContextAdapter : DmContext
private readonly IServiceProvider _services; private readonly IServiceProvider _services;
private readonly Lazy<IEmbedBuilderService> _ebs;
private readonly Lazy<IBotStrings> _botStrings; private readonly Lazy<IBotStrings> _botStrings;
private readonly Lazy<ILocalization> _localization; private readonly Lazy<ILocalization> _localization;
@@ -32,14 +31,10 @@ public sealed class DmContextAdapter : DmContext
Bot = ctx.Client.CurrentUser; Bot = ctx.Client.CurrentUser;
_ebs = new(_services.GetRequiredService<IEmbedBuilderService>());
_botStrings = new(_services.GetRequiredService<IBotStrings>); _botStrings = new(_services.GetRequiredService<IBotStrings>);
_localization = new(_services.GetRequiredService<ILocalization>()); _localization = new(_services.GetRequiredService<ILocalization>());
} }
public override EmbedBuilder Embed()
=> new EmbedBuilder();
public override string GetText(string key, object[]? args = null) public override string GetText(string key, object[]? args = null)
{ {
var cultureInfo = _localization.Value.GetCultureInfo(default(ulong?)); var cultureInfo = _localization.Value.GetCultureInfo(default(ulong?));

View File

@@ -5,7 +5,6 @@ public sealed class GuildContextAdapter : GuildContext
{ {
private readonly IServiceProvider _services; private readonly IServiceProvider _services;
private readonly ICommandContext _ctx; private readonly ICommandContext _ctx;
private readonly Lazy<IEmbedBuilderService> _ebs;
private readonly Lazy<IBotStrings> _botStrings; private readonly Lazy<IBotStrings> _botStrings;
private readonly Lazy<ILocalization> _localization; private readonly Lazy<ILocalization> _localization;
@@ -18,9 +17,6 @@ public sealed class GuildContextAdapter : GuildContext
public override IGuildUser User { get; } public override IGuildUser User { get; }
public override EmbedBuilder Embed()
=> _ebs.Value.Create();
public GuildContextAdapter(ICommandContext ctx, IMedusaStrings strings, IServiceProvider services) public GuildContextAdapter(ICommandContext ctx, IMedusaStrings strings, IServiceProvider services)
{ {
if (ctx.Guild is not IGuild guild || ctx.Channel is not ITextChannel channel) if (ctx.Guild is not IGuild guild || ctx.Channel is not ITextChannel channel)
@@ -33,7 +29,6 @@ public sealed class GuildContextAdapter : GuildContext
Bot = ctx.Client.CurrentUser; Bot = ctx.Client.CurrentUser;
_services = services; _services = services;
_ebs = new(_services.GetRequiredService<IEmbedBuilderService>());
_botStrings = new(_services.GetRequiredService<IBotStrings>); _botStrings = new(_services.GetRequiredService<IBotStrings>);
_localization = new(_services.GetRequiredService<ILocalization>()); _localization = new(_services.GetRequiredService<ILocalization>());

View File

@@ -342,7 +342,6 @@ public sealed class MedusaLoaderService : IMedusaLoaderService, IReadyExecutor,
var sis = LoadSneksFromAssembly(safeName, a); var sis = LoadSneksFromAssembly(safeName, a);
typeReaders = LoadTypeReadersFromAssembly(a, strings); typeReaders = LoadTypeReadersFromAssembly(a, strings);
// todo allow this
if (sis.Count == 0) if (sis.Count == 0)
{ {
_kernel.Unload(safeName); _kernel.Unload(safeName);

View File

@@ -16,7 +16,6 @@ public abstract class NadekoModule : ModuleBase
public IBotStrings Strings { get; set; } public IBotStrings Strings { get; set; }
public ICommandHandler _cmdHandler { get; set; } public ICommandHandler _cmdHandler { get; set; }
public ILocalization _localization { get; set; } public ILocalization _localization { get; set; }
public IEmbedBuilderService _eb { get; set; }
public INadekoInteractionService _inter { get; set; } public INadekoInteractionService _inter { get; set; }
public IReplacementService repSvc { get; set; } public IReplacementService repSvc { get; set; }
public IMessageSenderService _sender { get; set; } public IMessageSenderService _sender { get; set; }
@@ -28,7 +27,7 @@ public abstract class NadekoModule : ModuleBase
=> Context; => Context;
public ResponseBuilder Response() public ResponseBuilder Response()
=> new ResponseBuilder(Strings, _eb) => new ResponseBuilder(Strings)
.Context(ctx); .Context(ctx);
protected override void BeforeExecute(CommandInfo command) protected override void BeforeExecute(CommandInfo command)

View File

@@ -3,5 +3,8 @@
public interface IMessageSenderService public interface IMessageSenderService
{ {
ResponseBuilder Response(IMessageChannel channel); ResponseBuilder Response(IMessageChannel channel);
ResponseBuilder Response(ICommandContext hannel); ResponseBuilder Response(ICommandContext ctx);
ResponseBuilder Response(IUser user);
ResponseBuilder Response(SocketMessageComponent smc);
} }

View File

@@ -2,10 +2,6 @@
public static class MessageChannelExtensions public static class MessageChannelExtensions
{ {
public static ResponseBuilder Response(this IMessageChannel channel, IBotStrings bs, IEmbedBuilderService ebs)
=> new ResponseBuilder(bs, ebs)
.Channel(channel);
// main overload that all other send methods reduce to // main overload that all other send methods reduce to
public static Task<IUserMessage> SendAsync( public static Task<IUserMessage> SendAsync(
this IMessageChannel channel, this IMessageChannel channel,
@@ -92,7 +88,7 @@ public static class MessageChannelExtensions
this IMessageChannel ch, this IMessageChannel ch,
EmbedBuilder? embed, EmbedBuilder? embed,
string plainText = "", string plainText = "",
IReadOnlyCollection<IEmbedBuilder>? embeds = null, IReadOnlyCollection<EmbedBuilder>? embeds = null,
NadekoInteraction? inter = null, NadekoInteraction? inter = null,
IUserMessage? replyTo = null) IUserMessage? replyTo = null)
=> ch.SendAsync(plainText, => ch.SendAsync(plainText,

View File

@@ -5,20 +5,27 @@ namespace NadekoBot.Extensions;
public sealed class MessageSenderService : IMessageSenderService, INService public sealed class MessageSenderService : IMessageSenderService, INService
{ {
private readonly IBotStrings _bs; private readonly IBotStrings _bs;
private readonly IEmbedBuilderService _ebs;
public MessageSenderService(IBotStrings bs, IEmbedBuilderService ebs) public MessageSenderService(IBotStrings bs)
{ {
_bs = bs; _bs = bs;
_ebs = ebs;
} }
public ResponseBuilder Response(IMessageChannel channel) public ResponseBuilder Response(IMessageChannel channel)
=> new ResponseBuilder(_bs, _ebs) => new ResponseBuilder(_bs)
.Channel(channel); .Channel(channel);
public ResponseBuilder Response(ICommandContext ctx) public ResponseBuilder Response(ICommandContext ctx)
=> new ResponseBuilder(_bs, _ebs) => new ResponseBuilder(_bs)
.Context(ctx); .Context(ctx);
public ResponseBuilder Response(IUser user)
=> new ResponseBuilder(_bs)
.User(user);
// todo fix interactions
public ResponseBuilder Response(SocketMessageComponent smc)
=> new ResponseBuilder(_bs)
.Channel(smc.Channel);
} }

View File

@@ -14,13 +14,14 @@ public sealed class ResponseBuilder
private object[] locParams = []; private object[] locParams = [];
private bool shouldReply = true; private bool shouldReply = true;
private readonly IBotStrings _bs; private readonly IBotStrings _bs;
private readonly IEmbedBuilderService _ebs;
private EmbedBuilder? embedBuilder = null; private EmbedBuilder? embedBuilder = null;
private NadekoInteraction? inter;
private Stream? fileStream = null;
private string? fileName = null;
public ResponseBuilder(IBotStrings bs, IEmbedBuilderService ebs) public ResponseBuilder(IBotStrings bs)
{ {
_bs = bs; _bs = bs;
_ebs = ebs;
} }
private MessageReference? CreateMessageReference(IMessageChannel targetChannel) private MessageReference? CreateMessageReference(IMessageChannel targetChannel)
@@ -43,8 +44,9 @@ public sealed class ResponseBuilder
failIfNotExists: false); failIfNotExists: false);
} }
public async Task<IUserMessage> SendAsync() public async Task<IUserMessage> SendAsync(bool ephemeral = false)
{ {
// todo use ephemeral in interactions
var targetChannel = InternalResolveChannel() ?? throw new ArgumentNullException(nameof(channel)); var targetChannel = InternalResolveChannel() ?? throw new ArgumentNullException(nameof(channel));
var msgReference = CreateMessageReference(targetChannel); var msgReference = CreateMessageReference(targetChannel);
@@ -53,6 +55,15 @@ public sealed class ResponseBuilder
if (sanitizeMentions) if (sanitizeMentions)
txt = txt?.SanitizeMentions(true); txt = txt?.SanitizeMentions(true);
if (this.fileStream is Stream stream)
return await targetChannel.SendFileAsync(stream,
filename: fileName,
txt,
embed: embed ?? embedBuilder?.Build(),
components: null,
allowedMentions: sanitizeMentions ? new(AllowedMentionTypes.Users) : AllowedMentions.All,
messageReference: msgReference);
return await targetChannel.SendMessageAsync( return await targetChannel.SendMessageAsync(
txt, txt,
embed: embed ?? embedBuilder?.Build(), embed: embed ?? embedBuilder?.Build(),
@@ -65,6 +76,7 @@ public sealed class ResponseBuilder
private ulong? InternalResolveGuildId(IMessageChannel? targetChannel) private ulong? InternalResolveGuildId(IMessageChannel? targetChannel)
=> ctx?.Guild?.Id ?? (targetChannel as ITextChannel)?.GuildId; => ctx?.Guild?.Id ?? (targetChannel as ITextChannel)?.GuildId;
// todo not good, has to go to the user
private IMessageChannel? InternalResolveChannel() private IMessageChannel? InternalResolveChannel()
=> channel ?? ctx?.Channel ?? msg?.Channel; => channel ?? ctx?.Channel ?? msg?.Channel;
@@ -188,20 +200,14 @@ public sealed class ResponseBuilder
private IUser? InternalResolveUser() private IUser? InternalResolveUser()
=> ctx?.User ?? user ?? msg?.Author; => ctx?.User ?? user ?? msg?.Author;
// todo embed colors
public ResponseBuilder Embed(EmbedBuilder eb) public ResponseBuilder Embed(EmbedBuilder eb)
{ {
embedBuilder = eb; embedBuilder = eb;
return this; return this;
} }
public ResponseBuilder Embed(Func<IEmbedBuilderService, EmbedBuilder> embedFactory)
{
// todo colors
this.embed = embedFactory(_ebs).Build();
return this;
}
public ResponseBuilder Channel(IMessageChannel channel) public ResponseBuilder Channel(IMessageChannel channel)
{ {
this.channel = channel; this.channel = channel;
@@ -238,9 +244,10 @@ public sealed class ResponseBuilder
return this; return this;
} }
public ResponseBuilder Interaction(NadekoInteraction inter) public ResponseBuilder Interaction(NadekoInteraction? interaction)
{ {
// todo implement // todo implement
inter = interaction;
return this; return this;
} }
@@ -249,4 +256,11 @@ public sealed class ResponseBuilder
embeds = inputEmbeds; embeds = inputEmbeds;
return this; return this;
} }
public ResponseBuilder FileName(Stream fileStream, string fileName)
{
this.fileStream = fileStream;
this.fileName = fileName;
return this;
}
} }

View File

@@ -13,7 +13,7 @@ public static class CurrencyServiceExtensions
// FUTURE should be a transaction // FUTURE should be a transaction
public static async Task<bool> TransferAsync( public static async Task<bool> TransferAsync(
this ICurrencyService cs, this ICurrencyService cs,
IEmbedBuilderService ebs, IMessageSenderService sender,
IUser from, IUser from,
IUser to, IUser to,
long amount, long amount,
@@ -29,17 +29,20 @@ public static class CurrencyServiceExtensions
{ {
try try
{ {
await to.SendConfirmAsync(ebs, await sender.Response(to)
string.IsNullOrWhiteSpace(note) .Confirm(string.IsNullOrWhiteSpace(note)
? $"Received {formattedAmount} from {from} " ? $"Received {formattedAmount} from {from} "
: $"Received {formattedAmount} from {from}: {note}"); : $"Received {formattedAmount} from {from}: {note}")
.SendAsync();
} }
catch catch
{ {
//ignored //ignored
} }
return true; return true;
} }
return false; return false;
} }
} }

View File

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

View File

@@ -8,7 +8,7 @@ public sealed class CommandsUtilityService : ICommandsUtilityService, INService
private readonly CommandHandler _ch; private readonly CommandHandler _ch;
private readonly IBotStrings _strings; private readonly IBotStrings _strings;
private readonly DiscordPermOverrideService _dpos; private readonly DiscordPermOverrideService _dpos;
private readonly IEmbedBuilderService _eb; private readonly IMessageSenderService _sender;
private readonly ILocalization _loc; private readonly ILocalization _loc;
private readonly IMedusaLoaderService _medusae; private readonly IMedusaLoaderService _medusae;
@@ -16,14 +16,14 @@ public sealed class CommandsUtilityService : ICommandsUtilityService, INService
CommandHandler ch, CommandHandler ch,
IBotStrings strings, IBotStrings strings,
DiscordPermOverrideService dpos, DiscordPermOverrideService dpos,
IEmbedBuilderService eb, IMessageSenderService sender,
ILocalization loc, ILocalization loc,
IMedusaLoaderService medusae) IMedusaLoaderService medusae)
{ {
_ch = ch; _ch = ch;
_strings = strings; _strings = strings;
_dpos = dpos; _dpos = dpos;
_eb = eb; _sender = sender;
_loc = loc; _loc = loc;
_medusae = medusae; _medusae = medusae;
} }

View File

@@ -60,31 +60,34 @@ public static class SocketMessageComponentExtensions
public static Task RespondAsync( public static Task RespondAsync(
this SocketMessageComponent ch, this SocketMessageComponent ch,
IEmbedBuilderService eb, IMessageSenderService sender,
string text, string text,
MsgType type, MsgType type,
bool ephemeral = false, bool ephemeral = false,
NadekoInteraction? inter = null) NadekoInteraction? inter = null)
{ {
var builder = new EmbedBuilder().WithDescription(text); var embed = new EmbedBuilder().WithDescription(text);
builder = (type switch embed = (type switch
{ {
MsgType.Error => builder.WithErrorColor(), MsgType.Error => embed.WithErrorColor(),
MsgType.Ok => builder.WithOkColor(), MsgType.Ok => embed.WithOkColor(),
MsgType.Pending => builder.WithPendingColor(), MsgType.Pending => embed.WithPendingColor(),
_ => throw new ArgumentOutOfRangeException(nameof(type)) _ => throw new ArgumentOutOfRangeException(nameof(type))
}); });
return ch.EmbedAsync(builder, inter: inter, ephemeral: ephemeral); return sender.Response(ch)
.Embed(embed)
.Interaction(inter)
.SendAsync(ephemeral: ephemeral);
} }
// embed title and optional footer overloads // embed title and optional footer overloads
public static Task RespondConfirmAsync( public static Task RespondConfirmAsync(
this SocketMessageComponent smc, this SocketMessageComponent smc,
IEmbedBuilderService eb, IMessageSenderService sender,
string text, string text,
bool ephemeral = false) bool ephemeral = false)
=> smc.RespondAsync(eb, text, MsgType.Ok, ephemeral); => smc.RespondAsync(sender, text, MsgType.Ok, ephemeral);
} }

View File

@@ -4,21 +4,6 @@ namespace NadekoBot.Extensions;
public static class UserExtensions public static class UserExtensions
{ {
public static async Task<IUserMessage> EmbedAsync(this IUser user, EmbedBuilder embed, string msg = "")
{
var ch = await user.CreateDMChannelAsync();
return await ch.EmbedAsync(embed, msg);
}
public static async Task<IUserMessage> SendAsync(this IUser user, SmartText text, bool sanitizeAll = false)
{
var ch = await user.CreateDMChannelAsync();
return await ch.SendAsync(text, sanitizeAll);
}
public static async Task<IUserMessage> SendConfirmAsync(this IUser user, IEmbedBuilderService eb, string text)
=> await user.SendMessageAsync("", embed: new EmbedBuilder().WithOkColor().WithDescription(text).Build());
// This method is used by everything that fetches the avatar from a user // This method is used by everything that fetches the avatar from a user
public static Uri RealAvatarUrl(this IUser usr, ushort size = 256) public static Uri RealAvatarUrl(this IUser usr, ushort size = 256)
=> usr.AvatarId is null ? new(usr.GetDefaultAvatarUrl()) : new Uri(usr.GetAvatarUrl(ImageFormat.Auto, size)); => usr.AvatarId is null ? new(usr.GetDefaultAvatarUrl()) : new Uri(usr.GetAvatarUrl(ImageFormat.Auto, size));