1
Fork 0
mirror of https://gitlab.com/Kwoth/nadekobot.git synced 2024-10-02 20:13:13 +00:00

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.
- `.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 log voice presence TTS
## [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>
/// <returns>A formatted localized string</returns>
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
// 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)
// => 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)
// => ch.EmbedAsync(ctx.Embed().WithErrorColor().WithDescription(msg));
// => _sender.Response(ch).Embed(ctx.Embed().WithErrorColor().WithDescription(msg)).SendAsync();
//
// // unlocalized
// 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
public ulong? LogVoicePresenceId { get; set; }
public ulong? LogVoicePresenceTTSId { 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 BotConfigService _bss;
private readonly IReplacementService _repSvc;
private readonly IMessageSenderService _sender;
public GreetService(
DiscordSocketClient client,
IBot bot,
DbService db,
BotConfigService bss,
IMessageSenderService sender,
IReplacementService repSvc)
{
_db = db;
_client = client;
_bss = bss;
_repSvc = repSvc;
_sender = sender;
_guildConfigsCache = new(bot.AllGuildConfigs.ToDictionary(g => g.GuildId, GreetSettings.Create));
@ -281,6 +284,7 @@ public class GreetService : INService, IReadyExecutor
FullMode = BoundedChannelFullMode.DropNewest
});
private async Task<bool> GreetDmUser(GreetSettings conf, IGuildUser user)
{
var completionSource = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
@ -298,32 +302,32 @@ public class GreetService : INService, IReadyExecutor
// .Build();
var repCtx = new ReplacementContext(client: _client, guild: user.Guild, users: user);
var text = SmartText.CreateFrom(conf.DmGreetMessageText);
text = await _repSvc.ReplaceAsync(text, repCtx);
var smartText = SmartText.CreateFrom(conf.DmGreetMessageText);
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
};
}
if (text is SmartEmbedText set)
if (smartText is SmartEmbedText set)
{
text = set with
smartText = set with
{
Footer = CreateFooterSource(user)
};
}
else if (text is SmartEmbedTextArray seta)
else if (smartText is SmartEmbedTextArray seta)
{
// if the greet dm message is a text array
var ebElem = seta.Embeds.LastOrDefault();
if (ebElem is null)
{
// if there are no embeds, add an embed with the footer
text = seta with
smartText = seta with
{
Embeds = new[]
{
@ -355,7 +359,7 @@ public class GreetService : INService, IReadyExecutor
}
}
await user.SendAsync(text);
await _sender.Response(user).Text(smartText).SendAsync();
}
catch
{

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -169,7 +169,7 @@ public partial class Gambling
}
else
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();
}
catch (ArgumentOutOfRangeException)

View file

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

View file

@ -109,7 +109,7 @@ public partial class Gambling
RepostCounter++;
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 { }
}
}

View file

@ -12,12 +12,15 @@ public class CurrencyEventsService : INService
private readonly GamblingConfigService _configService;
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;
_cs = cs;
_configService = configService;
_sender = sender;
}
public async Task<bool> TryCreateEventAsync(
@ -34,9 +37,9 @@ public class CurrencyEventsService : INService
ICurrencyEvent ce;
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)
ce = new GameStatusEvent(_client, _cs, g, ch, opts, embed);
ce = new GameStatusEvent(_client, _cs, g, ch, opts, _sender, embed);
else
return false;

View file

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

View file

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

View file

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

View file

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

View file

@ -20,9 +20,7 @@ public class ChatterBotService : IExecOnMessage
private readonly DiscordSocketClient _client;
private readonly IPermissionChecker _perms;
private readonly CommandHandler _cmd;
private readonly IBotStrings _strings;
private readonly IBotCredentials _creds;
private readonly IEmbedBuilderService _eb;
private readonly IHttpClientFactory _httpFactory;
private readonly IPatronageService _ps;
private readonly GamesConfigService _gcs;
@ -33,10 +31,8 @@ public class ChatterBotService : IExecOnMessage
IPermissionChecker perms,
IBot bot,
CommandHandler cmd,
IBotStrings strings,
IHttpClientFactory factory,
IBotCredentials creds,
IEmbedBuilderService eb,
IPatronageService ps,
GamesConfigService gcs,
IMessageSenderService sender)
@ -44,14 +40,12 @@ public class ChatterBotService : IExecOnMessage
_client = client;
_perms = perms;
_cmd = cmd;
_strings = strings;
_creds = creds;
_eb = eb;
_sender = sender;
_httpFactory = factory;
_ps = ps;
_perms = perms;
_gcs = gcs;
_sender = sender;
_flKey = new FeatureLimitKey()
{
@ -166,8 +160,7 @@ public class ChatterBotService : IExecOnMessage
{
if (ql.Quota == 0)
{
await channel
.Response(_strings, _eb)
await _sender.Response(channel)
.Error(null,
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.",
@ -178,7 +171,7 @@ public class ChatterBotService : IExecOnMessage
return true;
}
await channel.Response(_strings, _eb)
await _sender.Response(channel)
.Error(
null!,
$"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)
{
@ -60,7 +60,7 @@ public partial class Games
return;
}
var eb = GetEmbed(_eb, hangman);
var eb = GetEmbed(hangman);
eb.WithDescription(GetText(strs.hangman_game_started));
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 IHangmanSource _source;
private readonly IEmbedBuilderService _eb;
private readonly IMessageSenderService _sender;
private readonly GamesConfigService _gcs;
private readonly ICurrencyService _cs;
private readonly IMemoryCache _cdCache;
@ -17,13 +17,13 @@ public sealed class HangmanService : IHangmanService, IExecNoCommand
public HangmanService(
IHangmanSource source,
IEmbedBuilderService eb,
IMessageSenderService sender,
GamesConfigService gcs,
ICurrencyService cs,
IMemoryCache cdCache)
{
_source = source;
_eb = eb;
_sender = sender;
_gcs = gcs;
_cs = cs;
_cdCache = cdCache;
@ -116,7 +116,7 @@ public sealed class HangmanService : IHangmanService, IExecNoCommand
string content,
HangmanGame.State state)
{
var embed = Games.HangmanCommands.GetEmbed(_eb, state);
var embed = Games.HangmanCommands.GetEmbed(state);
if (state.GuessResult == HangmanGame.GuessResult.Guess)
embed.WithDescription($"{user} guessed the letter {content}!").WithOkColor();
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))
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 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
{
// todo fix all modifies
await Task.Delay(2000);
time -= 2;
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;
_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)
.Embed(eb => 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))
.Embed(embed)
.SendAsync();
if (_finishedUserIds.Count % 4 == 0)

View file

@ -26,7 +26,7 @@ public class TicTacToe
private readonly IBotStrings _strings;
private readonly DiscordSocketClient _client;
private readonly Options _options;
private readonly IEmbedBuilderService _eb;
private readonly IMessageSenderService _sender;
public TicTacToe(
IBotStrings strings,
@ -34,13 +34,13 @@ public class TicTacToe
ITextChannel channel,
IGuildUser firstUser,
Options options,
IEmbedBuilderService eb)
IMessageSenderService sender)
{
_channel = channel;
_strings = strings;
_client = client;
_options = options;
_eb = eb;
_sender = sender;
_users = new[] { firstUser, 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)
{
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;
}
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;
}
@ -144,7 +144,7 @@ public class TicTacToe
var del = previousMessage?.DeleteAsync();
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)
await del;
}
@ -166,7 +166,7 @@ public class TicTacToe
_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()
@ -259,7 +259,7 @@ public class TicTacToe
{
var del1 = msg.DeleteAsync();
var del2 = previousMessage?.DeleteAsync();
try { previousMessage = await _channel.EmbedAsync(GetEmbed(reason)); }
try { previousMessage = await _sender.Response(_channel).Embed(GetEmbed(reason)).SendAsync(); }
catch { }
try { await del1; }

View file

@ -35,7 +35,7 @@ public partial class Games
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);
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))
{
await Response().Error(GetText(strs.trivia_already_running)).SendAsync();
await Response().Error(strs.trivia_already_running).SendAsync();
await tg.TriggerQuestionAsync();
}
}

View file

@ -376,7 +376,7 @@ public sealed class Help : NadekoModule<HelpService>
}
var embed = _cus.GetCommandHelp(com, ctx.Guild);
await channel.EmbedAsync(embed);
await _sender.Response(channel).Embed(embed).SendAsync();
}
[Cmd]
@ -510,7 +510,7 @@ public sealed class Help : NadekoModule<HelpService>
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
- 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()
.WithAuthor(GetText(strs.playlists_page(num)), MUSIC_ICON_URL)
.WithDescription(string.Join("\n",
playlists.Select(r => GetText(strs.playlists(r.Id, r.Name, r.Author, r.Songs.Count)))))
.WithOkColor();
.WithAuthor(GetText(strs.playlists_page(num)), MUSIC_ICON_URL)
.WithDescription(string.Join("\n",
playlists.Select(r => GetText(strs.playlists(r.Id, r.Name, r.Author, r.Songs.Count)))))
.WithOkColor();
await Response().Embed(embed).SendAsync();
}
@ -111,7 +111,9 @@ public sealed partial class Music
mpl.Songs.Skip(cur * 20)
.Take(20)
.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,
20);
@ -151,11 +153,13 @@ public sealed partial class Music
await uow.SaveChangesAsync();
}
await Response().Embed(new EmbedBuilder()
.WithOkColor()
.WithTitle(GetText(strs.playlist_saved))
.AddField(GetText(strs.name), name)
.AddField(GetText(strs.id), playlist.Id.ToString())).SendAsync();
await Response()
.Embed(new EmbedBuilder()
.WithOkColor()
.WithTitle(GetText(strs.playlist_saved))
.AddField(GetText(strs.name), name)
.AddField(GetText(strs.id), playlist.Id.ToString()))
.SendAsync();
}
[Cmd]
@ -208,8 +212,9 @@ public sealed partial class Music
IUserMessage msg = null;
try
{
msg = await ctx.Channel.SendMessageAsync(
GetText(strs.attempting_to_queue(Format.Bold(mpl.Songs.Count.ToString()))));
msg = await Response()
.Pending(strs.attempting_to_queue(Format.Bold(mpl.Songs.Count.ToString())))
.SendAsync();
}
catch (Exception)
{

View file

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

View file

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

View file

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

View file

@ -29,7 +29,6 @@ public sealed class PatronageService
private readonly DbService _db;
private readonly DiscordSocketClient _client;
private readonly ISubscriptionHandler _subsHandler;
private readonly IEmbedBuilderService _eb;
private static readonly TypedKey<long> _quotaKey
= new($"quota:last_hourly_reset");
@ -43,7 +42,6 @@ public sealed class PatronageService
DbService db,
DiscordSocketClient client,
ISubscriptionHandler subsHandler,
IEmbedBuilderService eb,
IBotCache cache,
IBotCredsProvider creds,
IMessageSenderService sender)
@ -52,10 +50,9 @@ public sealed class PatronageService
_db = db;
_client = client;
_subsHandler = subsHandler;
_eb = eb;
_sender = sender;
_cache = cache;
_creds = creds;
_sender = sender;
}
public Task OnReadyAsync()
@ -310,12 +307,12 @@ public sealed class PatronageService
ins =>
{
var eb = new EmbedBuilder()
.WithPendingColor()
.WithTitle("Insufficient Patron Tier")
.AddField("For", $"{ins.FeatureType}: `{ins.Feature}`", true)
.AddField("Required Tier",
$"[{ins.RequiredTier.ToFullName()}](https://patreon.com/join/nadekobot)",
true);
.WithPendingColor()
.WithTitle("Insufficient Patron Tier")
.AddField("For", $"{ins.FeatureType}: `{ins.Feature}`", true)
.AddField("Required Tier",
$"[{ins.RequiredTier.ToFullName()}](https://patreon.com/join/nadekobot)",
true);
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.")
@ -333,15 +330,15 @@ public sealed class PatronageService
.Embed(eb)
.SendAsync();
else
_ = ctx.User.EmbedAsync(eb);
_ = _sender.Response(ctx).User(ctx.User).Embed(eb).SendAsync();
return true;
},
quota =>
{
var eb = new EmbedBuilder()
.WithPendingColor()
.WithTitle("Quota Limit Reached");
.WithPendingColor()
.WithTitle("Quota Limit Reached");
if (quota.IsOwnQuota || ctx.User.Id == ownerId)
{
@ -369,7 +366,7 @@ public sealed class PatronageService
.Embed(eb)
.SendAsync();
else
_ = ctx.User.EmbedAsync(eb);
_ = _sender.Response(ctx).User(ctx.User).Embed(eb).SendAsync();
return true;
});
@ -782,30 +779,30 @@ public sealed class PatronageService
return;
var eb = new EmbedBuilder()
.WithOkColor()
.WithTitle("❤️ Thank you for supporting NadekoBot! ❤️")
.WithDescription(
"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. 🎉")
.AddField("Tier", Format.Bold(patron.Tier.ToString()), true)
.AddField("Pledge", $"**{patron.Amount / 100.0f:N1}$**", true)
.AddField("Expires",
patron.ValidThru.AddDays(1).ToShortAndRelativeTimestampTag(),
true)
.AddField("Instructions",
"""
*- 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 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.*
*- 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.*
*- Permission guide can be found here if you're not familiar with it: <https://nadekobot.readthedocs.io/en/latest/permissions-system/>*
""",
inline: false)
.WithFooter($"platform id: {patron.UniquePlatformUserId}");
.WithOkColor()
.WithTitle("❤️ Thank you for supporting NadekoBot! ❤️")
.WithDescription(
"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. 🎉")
.AddField("Tier", Format.Bold(patron.Tier.ToString()), true)
.AddField("Pledge", $"**{patron.Amount / 100.0f:N1}$**", true)
.AddField("Expires",
patron.ValidThru.AddDays(1).ToShortAndRelativeTimestampTag(),
true)
.AddField("Instructions",
"""
*- 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 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.*
*- 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.*
*- Permission guide can be found here if you're not familiar with it: <https://nadekobot.readthedocs.io/en/latest/permissions-system/>*
""",
inline: false)
.WithFooter($"platform id: {patron.UniquePlatformUserId}");
await user.EmbedAsync(eb);
await _sender.Response(user).Embed(eb).SendAsync();
}
catch
{
@ -830,7 +827,7 @@ public sealed class PatronageService
try
{
var user = await _client.GetUserAsync(patron.UserId);
await user.SendAsync(text);
await _sender.Response(user).Text(text).SendAsync();
++succ;
}
catch

View file

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

View file

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

View file

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

View file

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

View file

@ -165,7 +165,7 @@ public partial class Searches
}
await AddYoutubeUrlToCacheAsync(query, result.Url);
await ctx.Channel.SendMessageAsync(result.Url);
await Response().Text(result.Url).SendAsync();
}
// [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.timezone), data.TimeZoneName, true);
await ctx.Channel.SendMessageAsync(embed: eb.Build());
await Response().Embed(eb).SendAsync();
}
[Cmd]
@ -441,7 +441,7 @@ public partial class Searches : NadekoModule<SearchesService>
if (data.Query.Pages[0].Missing || string.IsNullOrWhiteSpace(data.Query.Pages[0].FullUrl))
await Response().Error(strs.wiki_page_not_found).SendAsync();
else
await ctx.Channel.SendMessageAsync(data.Query.Pages[0].FullUrl);
await Response().Text(data.Query.Pages[0].FullUrl).SendAsync();
}
[Cmd]
@ -514,7 +514,7 @@ public partial class Searches : NadekoModule<SearchesService>
var url = Uri.EscapeDataString($"https://{target}.fandom.com/wiki/{title}");
var response = $@"`{GetText(strs.title)}` {title.SanitizeMentions()}
`{GetText(strs.url)}:` {url}";
await ctx.Channel.SendMessageAsync(response);
await Response().Text(response).SendAsync();
}
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.links), gameData.GetGenresString(), true)
// .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)

View file

@ -25,7 +25,7 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
private readonly ConcurrentHashSet<ulong> _deleteOnOfflineServers;
private readonly IPubSub _pubSub;
private readonly IEmbedBuilderService _eb;
private readonly IMessageSenderService _sender;
private readonly SearchesConfigService _config;
private readonly IReplacementService _repSvc;
@ -49,7 +49,7 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
IHttpClientFactory httpFactory,
IBot bot,
IPubSub pubSub,
IEmbedBuilderService eb,
IMessageSenderService sender,
SearchesConfigService config,
IReplacementService repSvc)
{
@ -57,7 +57,7 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
_client = client;
_strings = strings;
_pubSub = pubSub;
_eb = eb;
_sender = sender;
_config = config;
_repSvc = repSvc;
@ -285,7 +285,10 @@ public sealed class StreamNotificationService : INService, IReadyExecutor
? ""
: 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
if (_deleteOnOfflineServers.Contains(fs.GuildId))

View file

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

View file

@ -13,7 +13,7 @@ public sealed class GiveawayService : INService, IReadyExecutor
private readonly DbService _db;
private readonly IBotCredentials _creds;
private readonly DiscordSocketClient _client;
private readonly IEmbedBuilderService _eb;
private readonly IMessageSenderService _sender;
private readonly IBotStrings _strings;
private readonly ILocalization _localization;
private readonly IMemoryCache _cache;
@ -22,12 +22,12 @@ public sealed class GiveawayService : INService, IReadyExecutor
private readonly ConcurrentDictionary<int, GiveawayRerollData> _rerolls = new();
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;
_creds = creds;
_client = client;
_eb = eb;
_sender = sender;
_strings = strings;
_localization = localization;
_cache = cache;
@ -317,8 +317,7 @@ public sealed class GiveawayService : INService, IReadyExecutor
{Format.Code(winner.UserId.ToString())}
""";
var eb = _eb
.Create()
var eb = new EmbedBuilder()
.WithOkColor()
.WithTitle(GetText(strs.giveaway_ended))
.WithDescription(ga.Message)
@ -334,7 +333,7 @@ public sealed class GiveawayService : INService, IReadyExecutor
catch
{
_ = 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)
{
var eb = new EmbedBuilder()
.WithOkColor()
.WithTitle($"{GetText(strs.quote_id($"#{data.Id}"))} | {GetText(strs.response)}:")
.WithDescription(Format.Sanitize(data.Text).Replace("](", "]\\(").TrimTo(4096))
.AddField(GetText(strs.trigger), data.Keyword)
.WithFooter(
GetText(strs.created_by($"{data.AuthorName} ({data.AuthorId})")))
.Build();
.WithOkColor()
.WithTitle($"{GetText(strs.quote_id($"#{data.Id}"))} | {GetText(strs.response)}:")
.WithDescription(Format.Sanitize(data.Text).Replace("](", "]\\(").TrimTo(4096))
.AddField(GetText(strs.trigger), data.Keyword)
.WithFooter(
GetText(strs.created_by($"{data.AuthorName} ({data.AuthorId})")));
if (!(data.Text.Length > 4096))
{
await ctx.Channel.SendMessageAsync(embed: eb);
await Response().Embed(eb).SendAsync();
return;
}
// todo all send files should go through response system too
await ctx.Channel.SendFileAsync(
attachment: new FileAttachment(await data.Text.ToStream(), "quote.txt"),
embed: eb);
embed: eb.Build());
}
private async Task QuoteSearchinternalAsync(string? keyword, string textOrAuthor)
@ -168,10 +168,12 @@ public partial class Utility
if (quote is null)
return;
await ctx.Channel.SendMessageAsync($"`#{quote.Id}` 💬 "
+ quote.Keyword.ToLowerInvariant()
+ ": "
+ quote.Text.SanitizeAllMentions());
await Response()
.Confirm($"`#{quote.Id}` 💬 ",
quote.Keyword.ToLowerInvariant()
+ ": "
+ quote.Text.SanitizeAllMentions())
.SendAsync();
}
[Cmd]
@ -204,7 +206,7 @@ public partial class Utility
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;
}

View file

@ -11,25 +11,26 @@ namespace NadekoBot.Modules.Utility.Services;
public class RemindService : INService, IReadyExecutor, IRemindService
{
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);
private readonly DiscordSocketClient _client;
private readonly DbService _db;
private readonly IBotCredentials _creds;
private readonly IEmbedBuilderService _eb;
private readonly IMessageSenderService _sender;
private readonly CultureInfo _culture;
public RemindService(
DiscordSocketClient client,
DbService db,
IBotCredentials creds,
IEmbedBuilderService eb)
IMessageSenderService sender)
{
_client = client;
_db = db;
_creds = creds;
_eb = eb;
_sender = sender;
try
{
@ -120,7 +121,7 @@ public class RemindService : INService, IReadyExecutor, IRemindService
if (!string.IsNullOrWhiteSpace(dateString))
{
var now = DateTime.UtcNow;
if (!DateTime.TryParse(dateString, _culture, DateTimeStyles.None, out var dt))
{
Log.Warning("Invalid remind datetime format");
@ -162,6 +163,7 @@ public class RemindService : INService, IReadyExecutor, IRemindService
values[groupName] = value;
}
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)
{
await ch.SendMessageAsync(null, embed: set.GetEmbed().Build());
await _sender.Response(ch).Embed(set.GetEmbed()).SendAsync();
}
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
{
await ch.EmbedAsync(new EmbedBuilder()
.WithOkColor()
.WithTitle("Reminder")
.AddField("Created At",
r.DateAdded.HasValue ? r.DateAdded.Value.ToLongDateString() : "?")
.AddField("By",
(await ch.GetUserAsync(r.UserId))?.ToString() ?? r.UserId.ToString()),
r.Message);
await _sender.Response(ch)
.Embed(new EmbedBuilder()
.WithOkColor()
.WithTitle("Reminder")
.AddField("Created At",
r.DateAdded.HasValue ? r.DateAdded.Value.ToLongDateString() : "?")
.AddField("By",
(await ch.GetUserAsync(r.UserId))?.ToString() ?? r.UserId.ToString()))
.Text(r.Message)
.SendAsync();
}
}
catch (Exception ex)
@ -227,7 +231,8 @@ public class RemindService : INService, IReadyExecutor, IRemindService
public TimeSpan Time { get; set; }
}
public async Task AddReminderAsync(ulong userId,
public async Task AddReminderAsync(
ulong userId,
ulong targetId,
ulong? guildId,
bool isPrivate,
@ -242,7 +247,7 @@ public class RemindService : INService, IReadyExecutor, IRemindService
ServerId = guildId ?? 0,
IsPrivate = isPrivate,
When = time,
Message = message,
Message = message,
Type = reminderType
};

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -5,7 +5,6 @@ public sealed class GuildContextAdapter : GuildContext
{
private readonly IServiceProvider _services;
private readonly ICommandContext _ctx;
private readonly Lazy<IEmbedBuilderService> _ebs;
private readonly Lazy<IBotStrings> _botStrings;
private readonly Lazy<ILocalization> _localization;
@ -18,9 +17,6 @@ public sealed class GuildContextAdapter : GuildContext
public override IGuildUser User { get; }
public override EmbedBuilder Embed()
=> _ebs.Value.Create();
public GuildContextAdapter(ICommandContext ctx, IMedusaStrings strings, IServiceProvider services)
{
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;
_services = services;
_ebs = new(_services.GetRequiredService<IEmbedBuilderService>());
_botStrings = new(_services.GetRequiredService<IBotStrings>);
_localization = new(_services.GetRequiredService<ILocalization>());

View file

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

View file

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

View file

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

View file

@ -5,20 +5,27 @@ namespace NadekoBot.Extensions;
public sealed class MessageSenderService : IMessageSenderService, INService
{
private readonly IBotStrings _bs;
private readonly IEmbedBuilderService _ebs;
public MessageSenderService(IBotStrings bs, IEmbedBuilderService ebs)
public MessageSenderService(IBotStrings bs)
{
_bs = bs;
_ebs = ebs;
}
public ResponseBuilder Response(IMessageChannel channel)
=> new ResponseBuilder(_bs, _ebs)
=> new ResponseBuilder(_bs)
.Channel(channel);
public ResponseBuilder Response(ICommandContext ctx)
=> new ResponseBuilder(_bs, _ebs)
=> new ResponseBuilder(_bs)
.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 bool shouldReply = true;
private readonly IBotStrings _bs;
private readonly IEmbedBuilderService _ebs;
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;
_ebs = ebs;
}
private MessageReference? CreateMessageReference(IMessageChannel targetChannel)
@ -43,8 +44,9 @@ public sealed class ResponseBuilder
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 msgReference = CreateMessageReference(targetChannel);
@ -53,6 +55,15 @@ public sealed class ResponseBuilder
if (sanitizeMentions)
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(
txt,
embed: embed ?? embedBuilder?.Build(),
@ -65,6 +76,7 @@ public sealed class ResponseBuilder
private ulong? InternalResolveGuildId(IMessageChannel? targetChannel)
=> ctx?.Guild?.Id ?? (targetChannel as ITextChannel)?.GuildId;
// todo not good, has to go to the user
private IMessageChannel? InternalResolveChannel()
=> channel ?? ctx?.Channel ?? msg?.Channel;
@ -188,20 +200,14 @@ public sealed class ResponseBuilder
private IUser? InternalResolveUser()
=> ctx?.User ?? user ?? msg?.Author;
// todo embed colors
public ResponseBuilder Embed(EmbedBuilder eb)
{
embedBuilder = eb;
return this;
}
public ResponseBuilder Embed(Func<IEmbedBuilderService, EmbedBuilder> embedFactory)
{
// todo colors
this.embed = embedFactory(_ebs).Build();
return this;
}
public ResponseBuilder Channel(IMessageChannel channel)
{
this.channel = channel;
@ -238,9 +244,10 @@ public sealed class ResponseBuilder
return this;
}
public ResponseBuilder Interaction(NadekoInteraction inter)
public ResponseBuilder Interaction(NadekoInteraction? interaction)
{
// todo implement
inter = interaction;
return this;
}
@ -249,4 +256,11 @@ public sealed class ResponseBuilder
embeds = inputEmbeds;
return this;
}
public ResponseBuilder FileName(Stream fileStream, string fileName)
{
this.fileStream = fileStream;
this.fileName = fileName;
return this;
}
}

View file

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

View file

@ -1,79 +1,17 @@
#nullable disable
using NadekoBot.Common.Configs;
// todo remove
namespace NadekoBot.Services;
public interface IEmbedBuilderService
// todo remove
public sealed class DiscordEmbedBuilderWrapper
{
EmbedBuilder Create(ICommandContext ctx = null);
}
// 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 class EmbedBuilderService : IEmbedBuilderService, INService
{
private readonly BotConfigService _botConfigService;
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 IBotStrings _strings;
private readonly DiscordPermOverrideService _dpos;
private readonly IEmbedBuilderService _eb;
private readonly IMessageSenderService _sender;
private readonly ILocalization _loc;
private readonly IMedusaLoaderService _medusae;
@ -16,14 +16,14 @@ public sealed class CommandsUtilityService : ICommandsUtilityService, INService
CommandHandler ch,
IBotStrings strings,
DiscordPermOverrideService dpos,
IEmbedBuilderService eb,
IMessageSenderService sender,
ILocalization loc,
IMedusaLoaderService medusae)
{
_ch = ch;
_strings = strings;
_dpos = dpos;
_eb = eb;
_sender = sender;
_loc = loc;
_medusae = medusae;
}

View file

@ -60,31 +60,34 @@ public static class SocketMessageComponentExtensions
public static Task RespondAsync(
this SocketMessageComponent ch,
IEmbedBuilderService eb,
IMessageSenderService sender,
string text,
MsgType type,
bool ephemeral = false,
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.Ok => builder.WithOkColor(),
MsgType.Pending => builder.WithPendingColor(),
MsgType.Error => embed.WithErrorColor(),
MsgType.Ok => embed.WithOkColor(),
MsgType.Pending => embed.WithPendingColor(),
_ => 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
public static Task RespondConfirmAsync(
this SocketMessageComponent smc,
IEmbedBuilderService eb,
IMessageSenderService sender,
string text,
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 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
public static Uri RealAvatarUrl(this IUser usr, ushort size = 256)
=> usr.AvatarId is null ? new(usr.GetDefaultAvatarUrl()) : new Uri(usr.GetAvatarUrl(ImageFormat.Auto, size));