ProjectMakoto/ProjectMakoto/Commands/BaseCommand.cs

1720 lines
84 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Project Makoto
// Copyright (C) 2024 Fortunevale
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY
using DisCatSharp.Extensions.TwoFactorCommands.Enums;
namespace ProjectMakoto.Commands;
public abstract class BaseCommand
{
public SharedCommandContext ctx { private get; set; }
public Translations t { get; set; }
#region Execution
public virtual async Task<bool> BeforeExecution(SharedCommandContext ctx)
{
return true;
}
public abstract Task ExecuteCommand(SharedCommandContext ctx, Dictionary<string, object> arguments = null);
public async Task TransferCommand(SharedCommandContext ctx, Dictionary<string, object> arguments = null)
{
this.t = ctx.Bot.LoadedTranslations;
this.ctx = ctx;
ctx.Transferred = true;
if (await this.BasePreExecutionCheck())
await this.ExecuteCommand(this.ctx, arguments).Add(ctx.Bot, this.ctx);
}
public async Task ExecuteCommand(CommandContext ctx, Bot _bot, Dictionary<string, object> arguments = null)
{
this.ctx = new SharedCommandContext(this, ctx, _bot);
this.t = _bot.LoadedTranslations;
if (await this.BasePreExecutionCheck())
await this.ExecuteCommand(this.ctx, arguments).Add(_bot, this.ctx);
}
public async Task ExecuteCommand(InteractionContext ctx, Bot _bot, Dictionary<string, object> arguments = null, bool Ephemeral = true, bool InitiateInteraction = true, bool InteractionInitiated = false)
{
this.ctx = new SharedCommandContext(this, ctx, _bot);
this.t = _bot.LoadedTranslations;
await Task.Run(async () =>
{
if (InitiateInteraction)
await ctx.CreateResponseAsync(InteractionResponseType.DeferredChannelMessageWithSource, new DiscordInteractionResponseBuilder()
{
IsEphemeral = Ephemeral
});
this.ctx.RespondedToInitial = InitiateInteraction;
if (InteractionInitiated)
this.ctx.RespondedToInitial = true;
if (await this.BasePreExecutionCheck())
await this.ExecuteCommand(this.ctx, arguments).Add(_bot, this.ctx);
}).Add(_bot, this.ctx);
}
public async Task ExecuteCommandWith2FA(InteractionContext ctx, Bot _bot, Dictionary<string, object> arguments = null)
{
this.ctx = new SharedCommandContext(this, ctx, _bot);
this.t = _bot.LoadedTranslations;
await Task.Run(async () =>
{
this.ctx.RespondedToInitial = false;
if (!this.ctx.Bot.status.LoadedConfig.IsDev)
if (!ctx.Client.CheckTwoFactorEnrollmentFor(ctx.User.Id))
{
_ = ctx.CreateResponseAsync(InteractionResponseType.ChannelMessageWithSource, new DiscordInteractionResponseBuilder().AddEmbed(new DiscordEmbedBuilder()
{
Description = "`Please enroll in Two Factor Authentication via 'Enroll2FA'.`"
}.AsError(this.ctx)).AsEphemeral());
return;
}
else
{
if (_bot.Users[ctx.User.Id].LastSuccessful2FA.GetTimespanSince() > TimeSpan.FromMinutes(3))
{
this.ctx.RespondedToInitial = true;
var tfa = await ctx.RequestTwoFactorAsync();
if (tfa.Result is TwoFactorResult.ValidCode or TwoFactorResult.InvalidCode)
await this.SwitchToEvent(tfa.ComponentInteraction);
if (tfa.Result != TwoFactorResult.ValidCode)
{
_ = this.RespondOrEdit(new DiscordMessageBuilder().WithContent("Invalid Code."));
return;
}
_bot.Users[ctx.User.Id].LastSuccessful2FA = DateTime.UtcNow;
}
}
if (!this.ctx.RespondedToInitial)
await ctx.CreateResponseAsync(InteractionResponseType.DeferredChannelMessageWithSource, new DiscordInteractionResponseBuilder()
{
IsEphemeral = true
});
if (await this.BasePreExecutionCheck())
await this.ExecuteCommand(this.ctx, arguments).Add(_bot, this.ctx);
}).Add(_bot, this.ctx);
}
public async Task ExecuteCommand(ContextMenuContext ctx, Bot _bot, Dictionary<string, object> arguments = null, bool Ephemeral = true, bool InitiateInteraction = true, bool InteractionInitiated = false)
{
this.ctx = new SharedCommandContext(this, ctx, _bot);
this.t = _bot.LoadedTranslations;
await Task.Run(async () =>
{
if (InitiateInteraction)
await ctx.CreateResponseAsync(InteractionResponseType.DeferredChannelMessageWithSource, new DiscordInteractionResponseBuilder()
{
IsEphemeral = Ephemeral
});
this.ctx.RespondedToInitial = InitiateInteraction;
if (InteractionInitiated)
this.ctx.RespondedToInitial = true;
if (await this.BasePreExecutionCheck())
await this.ExecuteCommand(this.ctx, arguments).Add(_bot, this.ctx);
}).Add(_bot, this.ctx);
}
public async Task ExecuteCommand(ComponentInteractionCreateEventArgs ctx, DiscordClient client, string commandName, Bot _bot, Dictionary<string, object> arguments = null, bool Ephemeral = true, bool InitiateInteraction = true, bool InteractionInitiated = false)
{
this.ctx = new SharedCommandContext(this, ctx, client, commandName, _bot);
this.t = _bot.LoadedTranslations;
await Task.Run(async () =>
{
if (InitiateInteraction)
await ctx.Interaction.CreateResponseAsync(InteractionResponseType.DeferredChannelMessageWithSource, new DiscordInteractionResponseBuilder()
{
IsEphemeral = Ephemeral
});
this.ctx.RespondedToInitial = InitiateInteraction;
if (InteractionInitiated)
this.ctx.RespondedToInitial = true;
if (await this.BasePreExecutionCheck())
await this.ExecuteCommand(this.ctx, arguments).Add(_bot, this.ctx);
}).Add(_bot, ctx);
}
private async Task<bool> BasePreExecutionCheck()
{
if (this.t is null)
{
Log.Warning($"The translation were not set before the BasePreExecutionCheck()!");
this.t = this.ctx.Bot.LoadedTranslations;
}
if (this.ctx.Bot.Users.ContainsKey(this.ctx.User.Id) && !this.ctx.User.Locale.IsNullOrWhiteSpace() && this.ctx.DbUser.CurrentLocale != this.ctx.User.Locale)
{
this.ctx.DbUser.CurrentLocale = this.ctx.User.Locale;
Log.Debug("Updated language for User '{User}' to '{Locale}'", this.ctx.User.Id, this.ctx.User.Locale);
}
if (this.ctx.Bot.status.LoadedConfig.Discord.DisabledCommands.Contains(this.ctx.ParentCommandName))
{
this.SendDisabledCommandError(this.ctx.ParentCommandName);
return false;
}
if (this.ctx.Bot.status.LoadedConfig.Discord.DisabledCommands.Contains(this.ctx.CommandName))
{
this.SendDisabledCommandError(this.ctx.CommandName);
return false;
}
if (!this.ctx.Channel.IsPrivate)
{
if (this.ctx.Bot.Guilds.ContainsKey(this.ctx.Guild.Id) && !this.ctx.Guild.PreferredLocale.IsNullOrWhiteSpace() && this.ctx.Bot.Guilds[this.ctx.Guild.Id].CurrentLocale != this.ctx.Guild.PreferredLocale)
{
this.ctx.Bot.Guilds[this.ctx.Guild.Id].CurrentLocale = this.ctx.Guild.PreferredLocale;
Log.Debug("Updated language for Guild '{Guild}' to '{Locale}'", this.ctx.Guild.Id, this.ctx.Guild.PreferredLocale);
}
if (!(await this.CheckOwnPermissions(Permissions.SendMessages)))
return false;
if (!(await this.CheckOwnPermissions(Permissions.EmbedLinks)))
return false;
if (!(await this.CheckOwnPermissions(Permissions.AddReactions)))
return false;
if (!(await this.CheckOwnPermissions(Permissions.AccessChannels)))
return false;
if (!(await this.CheckOwnPermissions(Permissions.AttachFiles)))
return false;
if (!(await this.CheckOwnPermissions(Permissions.ManageMessages)))
return false;
if (!(await this.BeforeExecution(this.ctx)))
return false;
}
if ((this.ctx.Bot.objectedUsers.Contains(this.ctx.User.Id) || this.ctx.DbUser.Data.DeletionRequested) && this.ctx.CommandName != "data" && this.ctx.CommandName != "delete")
{
this.SendDataError();
return false;
}
if (this.ctx.Bot.bannedUsers.TryGetValue(this.ctx.User.Id, out var blacklistedUserDetails))
{
this.SendUserBanError(blacklistedUserDetails);
return false;
}
if (this.ctx.Bot.bannedGuilds.TryGetValue(this.ctx.Guild?.Id ?? 0, out var blacklistedGuildDetails))
{
this.SendGuildBanError(blacklistedGuildDetails);
return false;
}
return !this.ctx.User.IsBot;
}
#endregion
public async Task SwitchToEvent(ComponentInteractionCreateEventArgs e)
{
await e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredChannelMessageWithSource, new DiscordInteractionResponseBuilder()
{
IsEphemeral = true
});
this.ctx.RespondedToInitial = true;
this.ctx.OriginalComponentInteractionCreateEventArgs = e;
this.ctx.CommandType = Enums.CommandType.Event;
}
#region RespondOrEdit
public Task<DiscordMessage> RespondOrEdit(DiscordEmbed embed)
=> this.RespondOrEdit(new DiscordMessageBuilder().AddEmbed(embed));
public Task<DiscordMessage> RespondOrEdit(DiscordEmbedBuilder embed)
=> this.RespondOrEdit(new DiscordMessageBuilder().AddEmbed(embed.Build()));
public Task<DiscordMessage> RespondOrEdit(string content)
=> this.RespondOrEdit(new DiscordMessageBuilder().WithContent(content));
public async Task<DiscordMessage> RespondOrEdit(DiscordMessageBuilder discordMessageBuilder)
{
switch (this.ctx.CommandType)
{
case Enums.CommandType.ApplicationCommand:
{
DiscordWebhookBuilder discordWebhookBuilder = new();
var files = new Dictionary<string, Stream>();
foreach (var b in discordMessageBuilder.Files)
files.Add(b.Filename, b.Stream);
if (discordMessageBuilder.Components.IsNotNullAndNotEmpty())
_ = discordWebhookBuilder.AddComponents(discordMessageBuilder.Components);
_ = discordWebhookBuilder.AddEmbeds(discordMessageBuilder.Embeds);
_ = discordWebhookBuilder.AddFiles(files);
discordWebhookBuilder.Content = discordMessageBuilder.Content;
var msg = await this.ctx.OriginalInteractionContext.EditResponseAsync(discordWebhookBuilder);
this.ctx.ResponseMessage = msg;
return msg;
}
case Enums.CommandType.ContextMenu:
{
DiscordWebhookBuilder discordWebhookBuilder = new();
var files = new Dictionary<string, Stream>();
foreach (var b in discordMessageBuilder.Files)
files.Add(b.Filename, b.Stream);
if (discordMessageBuilder.Components.IsNotNullAndNotEmpty())
_ = discordWebhookBuilder.AddComponents(discordMessageBuilder.Components);
_ = discordWebhookBuilder.AddEmbeds(discordMessageBuilder.Embeds);
_ = discordWebhookBuilder.AddFiles(files);
discordWebhookBuilder.Content = discordMessageBuilder.Content;
var msg = await this.ctx.OriginalContextMenuContext.EditResponseAsync(discordWebhookBuilder);
this.ctx.ResponseMessage = msg;
return msg;
}
case Enums.CommandType.Event:
{
DiscordWebhookBuilder discordWebhookBuilder = new();
var files = new Dictionary<string, Stream>();
foreach (var b in discordMessageBuilder.Files)
files.Add(b.Filename, b.Stream);
if (discordMessageBuilder.Components.IsNotNullAndNotEmpty())
_ = discordWebhookBuilder.AddComponents(discordMessageBuilder.Components);
_ = discordWebhookBuilder.AddEmbeds(discordMessageBuilder.Embeds);
_ = discordWebhookBuilder.AddFiles(files);
discordWebhookBuilder.Content = discordMessageBuilder.Content;
var msg = await this.ctx.OriginalComponentInteractionCreateEventArgs.Interaction.EditOriginalResponseAsync(discordWebhookBuilder);
this.ctx.ResponseMessage = msg;
return msg;
}
case Enums.CommandType.PrefixCommand:
case Enums.CommandType.Custom:
{
if (this.ctx.ResponseMessage is not null)
{
if ((discordMessageBuilder.Files?.Count ?? 0) > 0)
_ = discordMessageBuilder.KeepAttachments(false);
_ = await this.ctx.ResponseMessage.ModifyAsync(discordMessageBuilder);
this.ctx.ResponseMessage = await this.ctx.ResponseMessage.Refetch();
return this.ctx.ResponseMessage;
}
var msg = await this.ctx.Channel.SendMessageAsync(discordMessageBuilder);
this.ctx.ResponseMessage = msg;
return msg;
}
}
throw new NotImplementedException();
}
#endregion
#region GetString
TVar[] GetDefaultVars()
=> new TVar[]
{
new("CurrentCommand", this.ctx.Prefix + this.ctx.CommandName, false),
new("Bot", this.ctx.CurrentUser.Mention, false),
new("BotName", this.ctx.Client.CurrentApplication.Name, false),
new("FullBot", this.ctx.CurrentUser.GetUsernameWithIdentifier(), false),
new("BotDisplayName", this.ctx.CurrentUser.GetUsernameWithIdentifier(), false),
new("User", this.ctx.User.Mention, false),
new("UserName", this.ctx.User.GetUsername(), false),
new("FullUser", this.ctx.User.GetUsernameWithIdentifier(), false),
new("UserDisplayName", this.ctx.Member?.DisplayName ?? this.ctx.User.GetUsername(), false),
};
public string GetString(SingleTranslationKey key)
=> this.GetString(key, false, Array.Empty<TVar>());
public string GetString(SingleTranslationKey key, params TVar[] vars)
=> this.GetString(key, false, vars);
public string GetString(SingleTranslationKey key, bool Code = false, params TVar[] vars)
=> key.Get(this.ctx.DbUser).Build(Code, vars.Concat(this.GetDefaultVars()).ToArray());
public string GetString(MultiTranslationKey key)
=> this.GetString(key, false, false, Array.Empty<TVar>());
public string GetString(MultiTranslationKey key, params TVar[] vars)
=> this.GetString(key, false, false, vars);
public string GetString(MultiTranslationKey key, bool Code = false, params TVar[] vars)
=> this.GetString(key, Code, false, vars);
public string GetString(MultiTranslationKey key, bool Code = false, bool UseBoldMarker = false, params TVar[] vars)
=> key.Get(this.ctx.DbUser).Build(Code, UseBoldMarker, vars.Concat(this.GetDefaultVars()).ToArray());
public string GetGuildString(SingleTranslationKey key)
=> this.GetGuildString(key, false, Array.Empty<TVar>());
public string GetGuildString(SingleTranslationKey key, params TVar[] vars)
=> this.GetGuildString(key, false, vars);
public string GetGuildString(SingleTranslationKey key, bool Code = false, params TVar[] vars)
=> key.Get(this.ctx.DbGuild).Build(Code, vars.Concat(this.GetDefaultVars()).ToArray());
public string GetGuildString(MultiTranslationKey key)
=> this.GetGuildString(key, false, false, Array.Empty<TVar>());
public string GetGuildString(MultiTranslationKey key, params TVar[] vars)
=> this.GetGuildString(key, false, false, vars);
public string GetGuildString(MultiTranslationKey key, bool Code = false, params TVar[] vars)
=> this.GetGuildString(key, Code, false, vars);
public string GetGuildString(MultiTranslationKey key, bool Code = false, bool UseBoldMarker = false, params TVar[] vars)
=> key.Get(this.ctx.DbGuild).Build(Code, UseBoldMarker, vars.Concat(this.GetDefaultVars()).ToArray());
#endregion
#region Selections
public async Task<InteractionResult<DiscordRole>> PromptRoleSelection(RolePromptConfiguration configuration = null, TimeSpan? timeOutOverride = null)
{
configuration ??= new();
timeOutOverride ??= TimeSpan.FromSeconds(120);
var CreateNewButton = new DiscordButtonComponent(ButtonStyle.Secondary, Guid.NewGuid().ToString(), this.GetString(this.t.Commands.Common.Prompts.CreateRoleForMe), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("")));
var DisableButton = new DiscordButtonComponent(ButtonStyle.Secondary, Guid.NewGuid().ToString(), configuration.DisableOption ?? this.GetString(this.t.Commands.Common.Prompts.Disable), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("❌")));
var EveryoneButton = new DiscordButtonComponent(ButtonStyle.Secondary, Guid.NewGuid().ToString(), this.GetString(this.t.Commands.Common.Prompts.SelectEveryone), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("👥")));
var ConfirmSelectionButton = new DiscordButtonComponent(ButtonStyle.Success, Guid.NewGuid().ToString(), this.GetString(this.t.Commands.Common.Prompts.ConfirmSelection), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("✅")));
var SelectionInteractionId = Guid.NewGuid().ToString();
DiscordRole FinalSelection = null;
var Selected = "";
var FinishedSelection = false;
var ExceptionOccurred = false;
Exception ThrownException = null;
async Task RefreshMessage()
{
var dropdown = new DiscordRoleSelectComponent(this.GetString(this.t.Commands.Common.Prompts.SelectARole), SelectionInteractionId, 1, 1, false);
var builder = new DiscordMessageBuilder().AddEmbed(new DiscordEmbedBuilder(this.ctx.ResponseMessage.Embeds[0]).AsAwaitingInput(this.ctx)).AddComponents(dropdown).WithContent(this.ctx.ResponseMessage.Content);
if (Selected.IsNullOrWhiteSpace())
_ = ConfirmSelectionButton.Disable();
else
_ = ConfirmSelectionButton.Enable();
List<DiscordComponent> components = new();
if (!configuration.CreateRoleOption.IsNullOrWhiteSpace())
components.Add(CreateNewButton);
if (!configuration.DisableOption.IsNullOrWhiteSpace())
components.Add(DisableButton);
if (configuration.IncludeEveryone)
components.Add(EveryoneButton);
if (components.Count != 0)
_ = builder.AddComponents(components);
_ = builder.AddComponents(MessageComponents.GetCancelButton(this.ctx.DbUser, this.ctx.Bot), ConfirmSelectionButton);
_ = await this.RespondOrEdit(builder);
}
_ = RefreshMessage();
Stopwatch sw = new();
sw.Start();
async Task RunInteraction(DiscordClient s, ComponentInteractionCreateEventArgs e)
{
_ = Task.Run(async () =>
{
try
{
if (e.Message?.Id == this.ctx.ResponseMessage.Id && e.User.Id == this.ctx.User.Id)
{
sw.Restart();
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
if (e.GetCustomId() == SelectionInteractionId)
{
Selected = e.Values[0];
try
{
var role = this.ctx.Guild.GetRole(Convert.ToUInt64(Selected));
if (role.IsManaged || this.ctx.Member.GetRoleHighestPosition() <= role.Position)
{
Selected = "";
_ = e.Interaction.CreateFollowupMessageAsync(new DiscordFollowupMessageBuilder().AsEphemeral().WithContent($"❌ {this.GetString(this.t.Commands.Common.Prompts.SelectedRoleUnavailable, true)}"));
}
}
catch { }
await RefreshMessage();
}
if (e.GetCustomId() == DisableButton.CustomId)
{
FinalSelection = null;
FinishedSelection = true;
}
if (e.GetCustomId() == CreateNewButton.CustomId)
{
FinalSelection = await this.ctx.Guild.CreateRoleAsync(configuration.CreateRoleOption);
FinishedSelection = true;
}
if (e.GetCustomId() == EveryoneButton.CustomId)
{
FinalSelection = this.ctx.Guild.EveryoneRole;
FinishedSelection = true;
}
else if (e.GetCustomId() == ConfirmSelectionButton.CustomId)
{
this.ctx.Client.ComponentInteractionCreated -= RunInteraction;
FinalSelection = this.ctx.Guild.GetRole(Convert.ToUInt64(Selected));
FinishedSelection = true;
}
else if (e.GetCustomId() == MessageComponents.GetCancelButton(this.ctx.DbUser, this.ctx.Bot).CustomId)
throw new CancelException();
}
}
catch (Exception ex)
{
ThrownException = ex;
ExceptionOccurred = true;
FinishedSelection = true;
}
});
}
this.ctx.Client.ComponentInteractionCreated += RunInteraction;
while (!FinishedSelection && sw.Elapsed <= timeOutOverride)
{
await Task.Delay(100);
}
this.ctx.Client.ComponentInteractionCreated -= RunInteraction;
_ = await this.RespondOrEdit(new DiscordMessageBuilder().AddEmbed(this.ctx.ResponseMessage.Embeds[0]).WithContent(this.ctx.ResponseMessage.Content));
if (ExceptionOccurred)
return new InteractionResult<DiscordRole>(ThrownException);
return sw.Elapsed >= timeOutOverride
? new InteractionResult<DiscordRole>(new TimedOutException())
: new InteractionResult<DiscordRole>(FinalSelection);
}
public Task<InteractionResult<DiscordChannel>> PromptChannelSelection(ChannelType? channelType = null, ChannelPromptConfiguration configuration = null, TimeSpan? timeOutOverride = null)
=> this.PromptChannelSelection(((channelType is null || !channelType.HasValue) ? null : new ChannelType[] { channelType.Value }), configuration, timeOutOverride);
public async Task<InteractionResult<DiscordChannel>> PromptChannelSelection(ChannelType[]? channelTypes = null, ChannelPromptConfiguration configuration = null, TimeSpan? timeOutOverride = null)
{
configuration ??= new();
timeOutOverride ??= TimeSpan.FromSeconds(120);
List<DiscordStringSelectComponentOption> FetchedChannels = new();
var CreateNewButton = new DiscordButtonComponent(ButtonStyle.Secondary, Guid.NewGuid().ToString(), this.GetString(this.t.Commands.Common.Prompts.CreateChannelForMe), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("")));
var DisableButton = new DiscordButtonComponent(ButtonStyle.Secondary, Guid.NewGuid().ToString(), configuration.DisableOption ?? this.GetString(this.t.Commands.Common.Prompts.Disable), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("❌")));
var ConfirmSelectionButton = new DiscordButtonComponent(ButtonStyle.Success, Guid.NewGuid().ToString(), this.GetString(this.t.Commands.Common.Prompts.ConfirmSelection), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("✅")));
var SelectionInteractionId = Guid.NewGuid().ToString();
DiscordChannel FinalSelection = null;
var Selected = "";
var FinishedSelection = false;
var ExceptionOccurred = false;
Exception ThrownException = null;
async Task RefreshMessage()
{
var dropdown = new DiscordChannelSelectComponent(this.GetString(this.t.Commands.Common.Prompts.SelectAChannel), channelTypes, SelectionInteractionId);
var builder = new DiscordMessageBuilder().AddEmbed(new DiscordEmbedBuilder(this.ctx.ResponseMessage.Embeds[0]).AsAwaitingInput(this.ctx)).AddComponents(dropdown).WithContent(this.ctx.ResponseMessage.Content);
if (Selected.IsNullOrWhiteSpace())
_ = ConfirmSelectionButton.Disable();
else
_ = ConfirmSelectionButton.Enable();
List<DiscordComponent> components = new();
if (configuration.CreateChannelOption is not null)
components.Add(CreateNewButton);
if (!configuration.DisableOption.IsNullOrWhiteSpace())
components.Add(DisableButton);
if (components.Count > 0)
_ = builder.AddComponents(components);
_ = builder.AddComponents(MessageComponents.GetCancelButton(this.ctx.DbUser, this.ctx.Bot), ConfirmSelectionButton);
_ = await this.RespondOrEdit(builder);
}
_ = RefreshMessage();
Stopwatch sw = new();
sw.Start();
async Task RunInteraction(DiscordClient s, ComponentInteractionCreateEventArgs e)
{
_ = Task.Run(async () =>
{
try
{
if (e.Message?.Id == this.ctx.ResponseMessage.Id && e.User.Id == this.ctx.User.Id)
{
sw.Restart();
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
if (e.GetCustomId() == SelectionInteractionId)
{
Selected = e.Values.First();
FetchedChannels = FetchedChannels.Select(x => new DiscordStringSelectComponentOption(x.Label, x.Value, x.Description, (x.Value == Selected), x.Emoji)).ToList();
await RefreshMessage();
}
else if (e.GetCustomId() == CreateNewButton.CustomId)
{
FinalSelection = await this.ctx.Guild.CreateChannelAsync(configuration.CreateChannelOption.Name, configuration.CreateChannelOption.ChannelType);
FinishedSelection = true;
}
else if (e.GetCustomId() == DisableButton.CustomId)
{
FinalSelection = null;
FinishedSelection = true;
}
else if (e.GetCustomId() == ConfirmSelectionButton.CustomId)
{
this.ctx.Client.ComponentInteractionCreated -= RunInteraction;
FinalSelection = this.ctx.Guild.GetChannel(Convert.ToUInt64(Selected));
FinishedSelection = true;
}
else if (e.GetCustomId() == MessageComponents.GetCancelButton(this.ctx.DbUser, this.ctx.Bot).CustomId)
throw new CancelException();
}
}
catch (Exception ex)
{
ThrownException = ex;
ExceptionOccurred = true;
FinishedSelection = true;
}
});
}
this.ctx.Client.ComponentInteractionCreated += RunInteraction;
while (!FinishedSelection && sw.Elapsed <= timeOutOverride)
{
await Task.Delay(100);
}
this.ctx.Client.ComponentInteractionCreated -= RunInteraction;
_ = await this.RespondOrEdit(new DiscordMessageBuilder().AddEmbed(this.ctx.ResponseMessage.Embeds[0]).WithContent(this.ctx.ResponseMessage.Content));
if (ExceptionOccurred)
return new InteractionResult<DiscordChannel>(ThrownException);
return sw.Elapsed >= timeOutOverride
? new InteractionResult<DiscordChannel>(new TimedOutException())
: new InteractionResult<DiscordChannel>(FinalSelection);
}
public async Task<InteractionResult<string>> PromptCustomSelection(IEnumerable<DiscordStringSelectComponentOption> options, string? CustomPlaceHolder = null, TimeSpan? timeOutOverride = null)
{
timeOutOverride ??= TimeSpan.FromSeconds(120);
CustomPlaceHolder ??= this.GetString(this.t.Commands.Common.Prompts.SelectAnOption);
var ConfirmSelectionButton = new DiscordButtonComponent(ButtonStyle.Success, Guid.NewGuid().ToString(), this.GetString(this.t.Commands.Common.Prompts.ConfirmSelection), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("✅")));
var PrevPageButton = new DiscordButtonComponent(ButtonStyle.Primary, Guid.NewGuid().ToString(), this.GetString(this.t.Common.PreviousPage), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("◀")));
var NextPageButton = new DiscordButtonComponent(ButtonStyle.Primary, Guid.NewGuid().ToString(), this.GetString(this.t.Common.NextPage), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("▶")));
var CurrentPage = 0;
var SelectionInteractionId = Guid.NewGuid().ToString();
string FinalSelection = null;
var Selected = options.FirstOrDefault(x => x.Default, null)?.Value ?? "";
var FinishedSelection = false;
var ExceptionOccurred = false;
Exception ThrownException = null;
while (!Selected.IsNullOrWhiteSpace() && !options.Skip(CurrentPage * 25).Take(25).Any(x => x.Value == Selected))
{
if (!options.Skip(CurrentPage * 25).Take(25).Any())
{
CurrentPage = 0;
break;
}
CurrentPage++;
}
async Task RefreshMessage()
{
var dropdown = new DiscordStringSelectComponent(CustomPlaceHolder, options.Skip(CurrentPage * 25).Take(25).Select(x => new DiscordStringSelectComponentOption(x.Label, x.Value, x.Description, (x.Value == Selected), x.Emoji)), SelectionInteractionId);
var builder = new DiscordMessageBuilder().AddEmbed(new DiscordEmbedBuilder(this.ctx.ResponseMessage.Embeds[0]).AsAwaitingInput(this.ctx)).AddComponents(dropdown).WithContent(this.ctx.ResponseMessage.Content);
_ = NextPageButton.SetState(options.Skip(CurrentPage * 25).Count() <= 25);
_ = PrevPageButton.SetState(CurrentPage == 0);
_ = builder.AddComponents(PrevPageButton, NextPageButton);
if (Selected.IsNullOrWhiteSpace())
_ = ConfirmSelectionButton.Disable();
else
_ = ConfirmSelectionButton.Enable();
_ = builder.AddComponents(MessageComponents.GetCancelButton(this.ctx.DbUser, this.ctx.Bot), ConfirmSelectionButton);
_ = await this.RespondOrEdit(builder);
}
_ = RefreshMessage();
Stopwatch sw = new();
sw.Start();
async Task RunInteraction(DiscordClient s, ComponentInteractionCreateEventArgs e)
{
_ = Task.Run(async () =>
{
try
{
if (e.Message?.Id == this.ctx.ResponseMessage.Id && e.User.Id == this.ctx.User.Id)
{
sw.Restart();
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
if (e.GetCustomId() == SelectionInteractionId)
{
Selected = e.Values.First();
await RefreshMessage();
}
else if (e.GetCustomId() == ConfirmSelectionButton.CustomId)
{
this.ctx.Client.ComponentInteractionCreated -= RunInteraction;
FinalSelection = Selected;
FinishedSelection = true;
}
else if (e.GetCustomId() == PrevPageButton.CustomId)
{
CurrentPage--;
await RefreshMessage();
}
else if (e.GetCustomId() == NextPageButton.CustomId)
{
CurrentPage++;
await RefreshMessage();
}
else if (e.GetCustomId() == MessageComponents.GetCancelButton(this.ctx.DbUser, this.ctx.Bot).CustomId)
throw new CancelException();
}
}
catch (Exception ex)
{
ThrownException = ex;
ExceptionOccurred = true;
FinishedSelection = true;
}
});
}
this.ctx.Client.ComponentInteractionCreated += RunInteraction;
while (!FinishedSelection && sw.Elapsed <= timeOutOverride)
{
await Task.Delay(100);
}
this.ctx.Client.ComponentInteractionCreated -= RunInteraction;
_ = await this.RespondOrEdit(new DiscordMessageBuilder().AddEmbed(this.ctx.ResponseMessage.Embeds[0]).WithContent(this.ctx.ResponseMessage.Content));
if (ExceptionOccurred)
return new InteractionResult<string>(ThrownException);
return sw.Elapsed >= timeOutOverride
? new InteractionResult<string>(new TimedOutException())
: new InteractionResult<string>(FinalSelection);
}
#endregion
#region Modals
public Task<InteractionResult<ComponentInteractionCreateEventArgs>> PromptModalWithRetry(DiscordInteraction interaction, DiscordInteractionModalBuilder builder, bool ResetToOriginalEmbed = false, TimeSpan? timeOutOverride = null)
=> this.PromptModalWithRetry(interaction, builder, null, ResetToOriginalEmbed, timeOutOverride);
public async Task<InteractionResult<ComponentInteractionCreateEventArgs>> PromptModalWithRetry(DiscordInteraction interaction, DiscordInteractionModalBuilder builder, DiscordEmbedBuilder customEmbed = null, bool ResetToOriginalEmbed = false, TimeSpan? timeOutOverride = null, bool open = true)
{
timeOutOverride ??= TimeSpan.FromMinutes(15);
var oriEmbed = this.ctx.ResponseMessage.Embeds[0];
var ReOpen = new DiscordButtonComponent(ButtonStyle.Primary, Guid.NewGuid().ToString(), this.GetString(this.t.Commands.Common.Prompts.ReOpenModal), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("🔄")));
_ = await this.RespondOrEdit(new DiscordMessageBuilder().AddEmbed(customEmbed ?? new DiscordEmbedBuilder
{
Description = this.GetString(this.t.Commands.Common.Prompts.WaitingForModalResponse, true)
}.AsAwaitingInput(this.ctx)).AddComponents(new List<DiscordComponent> { ReOpen, MessageComponents.GetCancelButton(this.ctx.DbUser, this.ctx.Bot) }));
ComponentInteractionCreateEventArgs FinishedInteraction = null;
var FinishedSelection = false;
var ExceptionOccurred = false;
var Cancelled = false;
Exception ThrownException = null;
if (open)
await interaction.CreateInteractionModalResponseAsync(builder);
this.ctx.Client.ComponentInteractionCreated += RunInteraction;
async Task RunInteraction(DiscordClient s, ComponentInteractionCreateEventArgs e)
{
_ = Task.Run(async () =>
{
try
{
if (e.Message?.Id == this.ctx.ResponseMessage.Id && e.User.Id == this.ctx.User.Id)
{
if (e.GetCustomId() == builder.CustomId)
{
this.ctx.Client.ComponentInteractionCreated -= RunInteraction;
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
FinishedInteraction = e;
FinishedSelection = true;
}
else if (e.GetCustomId() == ReOpen.CustomId)
{
await e.Interaction.CreateInteractionModalResponseAsync(builder);
}
else if (e.GetCustomId() == MessageComponents.GetCancelButton(this.ctx.DbUser, this.ctx.Bot).CustomId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
throw new CancelException();
}
}
}
catch (Exception ex)
{
ThrownException = ex;
ExceptionOccurred = true;
FinishedSelection = true;
}
}).Add(this.ctx.Bot, this.ctx);
}
var TimeoutSeconds = (int)(timeOutOverride.Value.TotalSeconds * 2);
while (!FinishedSelection && !ExceptionOccurred && !Cancelled && TimeoutSeconds >= 0)
{
await Task.Delay(500);
TimeoutSeconds--;
}
this.ctx.Client.ComponentInteractionCreated -= RunInteraction;
if (ResetToOriginalEmbed)
_ = await this.RespondOrEdit(new DiscordMessageBuilder().AddEmbed(oriEmbed));
if (ExceptionOccurred)
return new InteractionResult<ComponentInteractionCreateEventArgs>(ThrownException);
return TimeoutSeconds <= 0
? new InteractionResult<ComponentInteractionCreateEventArgs>(new TimeoutException())
: new InteractionResult<ComponentInteractionCreateEventArgs>(FinishedInteraction);
}
public async Task<InteractionResult<TimeSpan>> PromptForTimeSpan(TimeSpan? MaxTime = null, TimeSpan? MinTime = null, TimeSpan? DefaultTime = null, bool ResetToOriginalEmbed = true, TimeSpan? timeOutOverride = null)
{
MinTime ??= TimeSpan.Zero;
MaxTime ??= TimeSpan.FromDays(356);
DefaultTime ??= TimeSpan.FromSeconds(30);
timeOutOverride ??= TimeSpan.FromSeconds(300);
if (DefaultTime > MaxTime)
DefaultTime = MaxTime;
if (DefaultTime < MinTime)
DefaultTime = MinTime;
var originalEmbed = ResetToOriginalEmbed ? this.ctx.ResponseMessage.Embeds : null;
var removeSeconds = new DiscordButtonComponent(ButtonStyle.Danger, Guid.NewGuid().ToString(), "10s", false, "".UnicodeToEmoji().ToComponent());
var removeSecond = new DiscordButtonComponent(ButtonStyle.Danger, Guid.NewGuid().ToString(), "1s", false, "".UnicodeToEmoji().ToComponent());
var addSecond = new DiscordButtonComponent(ButtonStyle.Success, Guid.NewGuid().ToString(), "1s", false, "".UnicodeToEmoji().ToComponent());
var addSeconds = new DiscordButtonComponent(ButtonStyle.Success, Guid.NewGuid().ToString(), "10s", false, "".UnicodeToEmoji().ToComponent());
var removeMinutes = new DiscordButtonComponent(ButtonStyle.Danger, Guid.NewGuid().ToString(), "10m", false, "".UnicodeToEmoji().ToComponent());
var removeMinute = new DiscordButtonComponent(ButtonStyle.Danger, Guid.NewGuid().ToString(), "1m", false, "".UnicodeToEmoji().ToComponent());
var addMinute = new DiscordButtonComponent(ButtonStyle.Success, Guid.NewGuid().ToString(), "1m", false, "".UnicodeToEmoji().ToComponent());
var addMinutes = new DiscordButtonComponent(ButtonStyle.Success, Guid.NewGuid().ToString(), "10m", false, "".UnicodeToEmoji().ToComponent());
var removeHours = new DiscordButtonComponent(ButtonStyle.Danger, Guid.NewGuid().ToString(), "10h", false, "".UnicodeToEmoji().ToComponent());
var removeHour = new DiscordButtonComponent(ButtonStyle.Danger, Guid.NewGuid().ToString(), "1h", false, "".UnicodeToEmoji().ToComponent());
var addHour = new DiscordButtonComponent(ButtonStyle.Success, Guid.NewGuid().ToString(), "1h", false, "".UnicodeToEmoji().ToComponent());
var addHours = new DiscordButtonComponent(ButtonStyle.Success, Guid.NewGuid().ToString(), "10h", false, "".UnicodeToEmoji().ToComponent());
var removeDays = new DiscordButtonComponent(ButtonStyle.Danger, Guid.NewGuid().ToString(), "10d", false, "".UnicodeToEmoji().ToComponent());
var removeDay = new DiscordButtonComponent(ButtonStyle.Danger, Guid.NewGuid().ToString(), "1d", false, "".UnicodeToEmoji().ToComponent());
var addDay = new DiscordButtonComponent(ButtonStyle.Success, Guid.NewGuid().ToString(), "1d", false, "".UnicodeToEmoji().ToComponent());
var addDays = new DiscordButtonComponent(ButtonStyle.Success, Guid.NewGuid().ToString(), "10d", false, "".UnicodeToEmoji().ToComponent());
var setExact = new DiscordButtonComponent(ButtonStyle.Secondary, Guid.NewGuid().ToString(), this.GetString(this.t.Commands.Common.Prompts.ManuallyDefineTimespan), false, "🕒".UnicodeToEmoji().ToComponent());
var confirmSelection = new DiscordButtonComponent(ButtonStyle.Success, Guid.NewGuid().ToString(), this.GetString(this.t.Commands.Common.Prompts.ConfirmSelection), false, "✅".UnicodeToEmoji().ToComponent());
var previousSuccessSelected = DefaultTime!.Value;
var currentSelectedTime = DefaultTime!.Value;
Task UpdateMessage()
{
if (currentSelectedTime > MaxTime || MinTime > currentSelectedTime)
currentSelectedTime = previousSuccessSelected;
previousSuccessSelected = currentSelectedTime;
foreach (var button in new List<DiscordButtonComponent>()
{
removeSeconds, removeSecond, addSecond, addSeconds,
removeMinutes, removeMinute, addMinute, addMinutes,
removeHours, removeHour, addHour, addHours,
removeDays, removeDay, addDay, addDays
})
_ = button.Enable();
if (currentSelectedTime - TimeSpan.FromSeconds(10) < MinTime)
_ = removeSeconds.Disable();
if (currentSelectedTime - TimeSpan.FromSeconds(1) < MinTime)
_ = removeSecond.Disable();
if (currentSelectedTime - TimeSpan.FromMinutes(10) < MinTime)
_ = removeMinutes.Disable();
if (currentSelectedTime - TimeSpan.FromMinutes(1) < MinTime)
_ = removeMinute.Disable();
if (currentSelectedTime - TimeSpan.FromHours(10) < MinTime)
_ = removeHours.Disable();
if (currentSelectedTime - TimeSpan.FromHours(1) < MinTime)
_ = removeHour.Disable();
if (currentSelectedTime - TimeSpan.FromDays(10) < MinTime)
_ = removeDays.Disable();
if (currentSelectedTime - TimeSpan.FromDays(1) < MinTime)
_ = removeDay.Disable();
if (currentSelectedTime + TimeSpan.FromSeconds(10) > MaxTime)
_ = addSeconds.Disable();
if (currentSelectedTime + TimeSpan.FromSeconds(1) > MaxTime)
_ = addSecond.Disable();
if (currentSelectedTime + TimeSpan.FromMinutes(10) > MaxTime)
_ = addMinutes.Disable();
if (currentSelectedTime + TimeSpan.FromMinutes(1) > MaxTime)
_ = addMinute.Disable();
if (currentSelectedTime + TimeSpan.FromHours(10) > MaxTime)
_ = addHours.Disable();
if (currentSelectedTime + TimeSpan.FromHours(1) > MaxTime)
_ = addHour.Disable();
if (currentSelectedTime + TimeSpan.FromDays(10) > MaxTime)
_ = addDays.Disable();
if (currentSelectedTime + TimeSpan.FromDays(1) > MaxTime)
_ = addDay.Disable();
var embed = new DiscordEmbedBuilder()
.WithDescription($"`{this.GetString(this.t.Commands.Common.Prompts.CurrentTimespan)}`: `{currentSelectedTime.GetHumanReadable(TimeFormat.Days, TranslationUtil.GetTranslatedHumanReadableConfig(this.ctx.DbUser, this.ctx.Bot, true))}`")
.AsAwaitingInput(this.ctx);
return this.RespondOrEdit(new DiscordMessageBuilder()
.AddEmbed(embed)
.AddComponents(removeSeconds, removeSecond, addSecond, addSeconds)
.AddComponents(removeMinutes, removeMinute, addMinute, addMinutes)
.AddComponents(removeHours, removeHour, addHour, addHours)
.AddComponents(removeDays, removeDay, addDay, addDays)
.AddComponents(setExact, MessageComponents.GetCancelButton(this.ctx.DbUser, this.ctx.Bot), confirmSelection));
}
await UpdateMessage();
var Finished = false;
var Cancelled = false;
var timeOut = Stopwatch.StartNew();
async Task Interaction(DiscordClient sender, ComponentInteractionCreateEventArgs e)
{
_ = Task.Run(async () =>
{
if (e.Message?.Id == this.ctx.ResponseMessage?.Id)
{
timeOut.Restart();
if (e.Id == removeSecond.CustomId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
currentSelectedTime = currentSelectedTime.Subtract(TimeSpan.FromSeconds(1));
await UpdateMessage();
}
else if (e.Id == removeSeconds.CustomId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
currentSelectedTime = currentSelectedTime.Subtract(TimeSpan.FromSeconds(10));
await UpdateMessage();
}
else if (e.Id == addSecond.CustomId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
currentSelectedTime = currentSelectedTime.Add(TimeSpan.FromSeconds(1));
await UpdateMessage();
}
else if (e.Id == addSeconds.CustomId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
currentSelectedTime = currentSelectedTime.Add(TimeSpan.FromSeconds(10));
await UpdateMessage();
}
else if (e.Id == removeMinute.CustomId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
currentSelectedTime = currentSelectedTime.Subtract(TimeSpan.FromMinutes(1));
await UpdateMessage();
}
else if (e.Id == removeMinutes.CustomId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
currentSelectedTime = currentSelectedTime.Subtract(TimeSpan.FromMinutes(10));
await UpdateMessage();
}
else if (e.Id == addMinute.CustomId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
currentSelectedTime = currentSelectedTime.Add(TimeSpan.FromMinutes(1));
await UpdateMessage();
}
else if (e.Id == addMinutes.CustomId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
currentSelectedTime = currentSelectedTime.Add(TimeSpan.FromMinutes(10));
await UpdateMessage();
}
else if (e.Id == removeHour.CustomId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
currentSelectedTime = currentSelectedTime.Subtract(TimeSpan.FromHours(1));
await UpdateMessage();
}
else if (e.Id == removeHours.CustomId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
currentSelectedTime = currentSelectedTime.Subtract(TimeSpan.FromHours(10));
await UpdateMessage();
}
else if (e.Id == addHour.CustomId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
currentSelectedTime = currentSelectedTime.Add(TimeSpan.FromHours(1));
await UpdateMessage();
}
else if (e.Id == addHours.CustomId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
currentSelectedTime = currentSelectedTime.Add(TimeSpan.FromHours(10));
await UpdateMessage();
}
else if (e.Id == removeDay.CustomId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
currentSelectedTime = currentSelectedTime.Subtract(TimeSpan.FromDays(1));
await UpdateMessage();
}
else if (e.Id == removeDays.CustomId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
currentSelectedTime = currentSelectedTime.Subtract(TimeSpan.FromDays(10));
await UpdateMessage();
}
else if (e.Id == addDay.CustomId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
currentSelectedTime = currentSelectedTime.Add(TimeSpan.FromDays(1));
await UpdateMessage();
}
else if (e.Id == addDays.CustomId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
currentSelectedTime = currentSelectedTime.Add(TimeSpan.FromDays(10));
await UpdateMessage();
}
else if (e.Id == confirmSelection.CustomId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
Finished = true;
}
else if (e.Id == MessageComponents.CancelButtonId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
Cancelled = true;
}
else if (e.Id == setExact.CustomId)
{
var modal = new DiscordInteractionModalBuilder().WithTitle(this.GetString(this.t.Commands.Common.Prompts.SelectATimeSpan)).WithCustomId(Guid.NewGuid().ToString());
if (MaxTime.Value.TotalDays >= 1)
_ = modal.AddTextComponent(new DiscordTextComponent(TextComponentStyle.Small, "days", this.GetString(this.t.Commands.Common.Prompts.TimespanDays)
.Build(new TVar("Max", ((int)MaxTime.Value.TotalDays))), "0", 1, 3, true, $"{currentSelectedTime.Days}"));
if (MaxTime.Value.TotalHours >= 1)
_ = modal.AddTextComponent(new DiscordTextComponent(TextComponentStyle.Small, "hours", this.GetString(this.t.Commands.Common.Prompts.TimespanHours)
.Build(new TVar("Max", (MaxTime.Value.TotalHours >= 24 ? "23" : $"{((int)MaxTime.Value.TotalHours)}"))), "0", 1, 2, true, $"{currentSelectedTime.Hours}"));
if (MaxTime.Value.TotalMinutes >= 1)
_ = modal.AddTextComponent(new DiscordTextComponent(TextComponentStyle.Small, "minutes", this.GetString(this.t.Commands.Common.Prompts.TimespanMinutes)
.Build(new TVar("Max", (MaxTime.Value.TotalMinutes >= 60 ? "59" : $"{((int)MaxTime.Value.TotalMinutes)}"))), $"0", 1, 2, true, $"{currentSelectedTime.Minutes}"));
_ = modal.AddTextComponent(new DiscordTextComponent(TextComponentStyle.Small, "seconds", this.GetString(this.t.Commands.Common.Prompts.TimespanSeconds)
.Build(new TVar("Max", 59)), "0", 1, 2, true, $"{currentSelectedTime.Seconds}"));
var ModalResult = await this.PromptModalWithRetry(e.Interaction, modal, true, timeOutOverride.Value.Subtract(timeOut.Elapsed));
if (!ModalResult.Failed)
{
try
{
var Response = ModalResult.Result;
var modalLength = TimeSpan.FromSeconds(0);
if ((Response.Interaction.Data.Components.Any(x => x.CustomId == "seconds") && !Response.Interaction.Data.Components.First(x => x.CustomId == "seconds").Value.IsDigitsOnly()) ||
(Response.Interaction.Data.Components.Any(x => x.CustomId == "minutes") && !Response.Interaction.Data.Components.First(x => x.CustomId == "minutes").Value.IsDigitsOnly()) ||
(Response.Interaction.Data.Components.Any(x => x.CustomId == "hours") && !Response.Interaction.Data.Components.First(x => x.CustomId == "hours").Value.IsDigitsOnly()) ||
(Response.Interaction.Data.Components.Any(x => x.CustomId == "days") && !Response.Interaction.Data.Components.First(x => x.CustomId == "days").Value.IsDigitsOnly()))
throw new InvalidOperationException("Invalid TimeSpan");
var seconds = Response.Interaction.Data.Components.Any(x => x.CustomId == "seconds") ? Convert.ToDouble(Convert.ToUInt32(Response.Interaction.Data.Components.First(x => x.CustomId == "seconds").Value)) : 0;
var minutes = Response.Interaction.Data.Components.Any(x => x.CustomId == "minutes") ? Convert.ToDouble(Convert.ToUInt32(Response.Interaction.Data.Components.First(x => x.CustomId == "minutes").Value)) : 0;
var hours = Response.Interaction.Data.Components.Any(x => x.CustomId == "hours") ? Convert.ToDouble(Convert.ToUInt32(Response.Interaction.Data.Components.First(x => x.CustomId == "hours").Value)) : 0;
var days = Response.Interaction.Data.Components.Any(x => x.CustomId == "days") ? Convert.ToDouble(Convert.ToUInt32(Response.Interaction.Data.Components.First(x => x.CustomId == "days").Value)) : 0;
modalLength = modalLength.Add(TimeSpan.FromSeconds(seconds));
modalLength = modalLength.Add(TimeSpan.FromMinutes(minutes));
modalLength = modalLength.Add(TimeSpan.FromHours(hours));
modalLength = modalLength.Add(TimeSpan.FromDays(days));
currentSelectedTime = modalLength;
}
catch { }
}
await UpdateMessage();
}
}
}).Add(this.ctx.Bot, this.ctx);
}
this.ctx.Client.ComponentInteractionCreated += Interaction;
while (!Finished && !Cancelled && timeOut.ElapsedMilliseconds < timeOutOverride.Value.TotalMilliseconds)
await Task.Delay(1000);
this.ctx.Client.ComponentInteractionCreated -= Interaction;
if (!Finished && !Cancelled && timeOut.ElapsedMilliseconds < timeOutOverride.Value.TotalMilliseconds)
return new InteractionResult<TimeSpan>(new TimedOutException());
if (Cancelled)
return new InteractionResult<TimeSpan>(new CancelException());
if (ResetToOriginalEmbed)
_ = await this.RespondOrEdit(new DiscordMessageBuilder().AddEmbeds(originalEmbed));
return currentSelectedTime > MaxTime || currentSelectedTime < MinTime
? new InteractionResult<TimeSpan>(new InvalidOperationException("Invalid TimeSpan"))
: new InteractionResult<TimeSpan>(currentSelectedTime);
}
public async Task<InteractionResult<DateTime>> PromptModalForDateTime(DateTime? defaultTime = null, bool ResetToOriginalEmbed = true, TimeSpan? timeOutOverride = null)
{
timeOutOverride ??= TimeSpan.FromMinutes(2);
defaultTime ??= DateTime.UtcNow;
var originalEmbed = ResetToOriginalEmbed ? this.ctx.ResponseMessage.Embeds : null;
var removeMinutes = new DiscordButtonComponent(ButtonStyle.Danger, Guid.NewGuid().ToString(), "10m", false, "".UnicodeToEmoji().ToComponent());
var removeMinute = new DiscordButtonComponent(ButtonStyle.Danger, Guid.NewGuid().ToString(), "1m", false, "".UnicodeToEmoji().ToComponent());
var addMinute = new DiscordButtonComponent(ButtonStyle.Success, Guid.NewGuid().ToString(), "1m", false, "".UnicodeToEmoji().ToComponent());
var addMinutes = new DiscordButtonComponent(ButtonStyle.Success, Guid.NewGuid().ToString(), "10m", false, "".UnicodeToEmoji().ToComponent());
var removeHours = new DiscordButtonComponent(ButtonStyle.Danger, Guid.NewGuid().ToString(), "10h", false, "".UnicodeToEmoji().ToComponent());
var removeHour = new DiscordButtonComponent(ButtonStyle.Danger, Guid.NewGuid().ToString(), "1h", false, "".UnicodeToEmoji().ToComponent());
var addHour = new DiscordButtonComponent(ButtonStyle.Success, Guid.NewGuid().ToString(), "1h", false, "".UnicodeToEmoji().ToComponent());
var addHours = new DiscordButtonComponent(ButtonStyle.Success, Guid.NewGuid().ToString(), "10h", false, "".UnicodeToEmoji().ToComponent());
var removeDays = new DiscordButtonComponent(ButtonStyle.Danger, Guid.NewGuid().ToString(), "10d", false, "".UnicodeToEmoji().ToComponent());
var removeDay = new DiscordButtonComponent(ButtonStyle.Danger, Guid.NewGuid().ToString(), "1d", false, "".UnicodeToEmoji().ToComponent());
var addDay = new DiscordButtonComponent(ButtonStyle.Success, Guid.NewGuid().ToString(), "1d", false, "".UnicodeToEmoji().ToComponent());
var addDays = new DiscordButtonComponent(ButtonStyle.Success, Guid.NewGuid().ToString(), "10d", false, "".UnicodeToEmoji().ToComponent());
var setExact = new DiscordButtonComponent(ButtonStyle.Secondary, Guid.NewGuid().ToString(), this.GetString(this.t.Commands.Common.Prompts.ManuallyDefineDateTime), false, "🕒".UnicodeToEmoji().ToComponent());
var changeTimezone = new DiscordButtonComponent(ButtonStyle.Secondary, Guid.NewGuid().ToString(), this.GetString(this.t.Commands.Common.Prompts.SelectTimezone), false, "🌐".UnicodeToEmoji().ToComponent());
var confirmSelection = new DiscordButtonComponent(ButtonStyle.Success, Guid.NewGuid().ToString(), this.GetString(this.t.Commands.Common.Prompts.ConfirmSelection), false, "✅".UnicodeToEmoji().ToComponent());
var currentSelectedTime = defaultTime!.Value;
Task UpdateMessage()
{
var embed = new DiscordEmbedBuilder()
.WithDescription($"`{this.GetString(this.t.Commands.Common.Prompts.CurrentDateTime)}`: {currentSelectedTime.ToTimestamp()} ({currentSelectedTime.ToTimestamp(TimestampFormat.LongDateTime)})")
.AsAwaitingInput(this.ctx);
return this.RespondOrEdit(new DiscordMessageBuilder()
.AddEmbed(embed)
.AddComponents(removeMinutes, removeMinute, addMinute, addMinutes)
.AddComponents(removeHours, removeHour, addHour, addHours)
.AddComponents(removeDays, removeDay, addDay, addDays)
.AddComponents(changeTimezone, setExact)
.AddComponents(MessageComponents.GetCancelButton(this.ctx.DbUser, this.ctx.Bot), confirmSelection));
}
await UpdateMessage();
var Finished = false;
var Cancelled = false;
var timeOut = Stopwatch.StartNew();
async Task Interaction(DiscordClient sender, ComponentInteractionCreateEventArgs e)
{
_ = Task.Run(async () =>
{
if (e.Message?.Id == this.ctx.ResponseMessage?.Id)
{
timeOut.Restart();
if (e.Id == removeMinute.CustomId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
currentSelectedTime = currentSelectedTime.Subtract(TimeSpan.FromMinutes(1));
}
else if (e.Id == removeMinutes.CustomId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
currentSelectedTime = currentSelectedTime.Subtract(TimeSpan.FromMinutes(10));
}
else if (e.Id == addMinute.CustomId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
currentSelectedTime = currentSelectedTime.Add(TimeSpan.FromMinutes(1));
}
else if (e.Id == addMinutes.CustomId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
currentSelectedTime = currentSelectedTime.Add(TimeSpan.FromMinutes(10));
}
else if (e.Id == removeHour.CustomId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
currentSelectedTime = currentSelectedTime.Subtract(TimeSpan.FromHours(1));
}
else if (e.Id == removeHours.CustomId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
currentSelectedTime = currentSelectedTime.Subtract(TimeSpan.FromHours(10));
}
else if (e.Id == addHour.CustomId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
currentSelectedTime = currentSelectedTime.Add(TimeSpan.FromHours(1));
}
else if (e.Id == addHours.CustomId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
currentSelectedTime = currentSelectedTime.Add(TimeSpan.FromHours(10));
}
else if (e.Id == removeDay.CustomId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
currentSelectedTime = currentSelectedTime.Subtract(TimeSpan.FromDays(1));
}
else if (e.Id == removeDays.CustomId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
currentSelectedTime = currentSelectedTime.Subtract(TimeSpan.FromDays(10));
}
else if (e.Id == addDay.CustomId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
currentSelectedTime = currentSelectedTime.Add(TimeSpan.FromDays(1));
}
else if (e.Id == addDays.CustomId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
currentSelectedTime = currentSelectedTime.Add(TimeSpan.FromDays(10));
}
else if (e.Id == confirmSelection.CustomId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
Finished = true;
return;
}
else if (e.Id == MessageComponents.CancelButtonId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
Cancelled = true;
return;
}
else if (e.Id == changeTimezone.CustomId)
{
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Common.Prompts.SelectTimezonePrompt, true)).AsAwaitingInput(this.ctx));
var promptResult = await this.PromptCustomSelection(TimeZoneInfo.GetSystemTimeZones()
.Select(x => new DiscordStringSelectComponentOption(x.DisplayName, x.Id, null, x.Id == (this.ctx.DbUser.Timezone ?? "UTC"))), null, timeOutOverride.Value.Subtract(timeOut.Elapsed));
if (promptResult.Failed)
{
await UpdateMessage();
return;
}
this.ctx.DbUser.Timezone = promptResult.Result;
}
else if (e.Id == setExact.CustomId)
{
var modalInteraction = e.Interaction;
if (this.ctx.DbUser.Timezone.IsNullOrWhiteSpace() || !TimeZoneInfo.GetSystemTimeZones().Any(x => x.Id == this.ctx.DbUser.Timezone))
{
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Common.Prompts.SelectTimezonePrompt, true)).AsAwaitingInput(this.ctx));
var promptResult = await this.PromptCustomSelection(TimeZoneInfo.GetSystemTimeZones()
.Select(x => new DiscordStringSelectComponentOption(x.DisplayName, x.Id, null, x.Id == (this.ctx.DbUser.Timezone ?? "UTC"))), null, timeOutOverride.Value.Subtract(timeOut.Elapsed));
if (promptResult.Failed)
{
await UpdateMessage();
return;
}
this.ctx.DbUser.Timezone = promptResult.Result;
modalInteraction = null;
}
var userTimezone = TimeZoneInfo.FindSystemTimeZoneById(this.ctx.DbUser.Timezone);
var userTime = TimeZoneInfo.ConvertTimeFromUtc(currentSelectedTime, userTimezone);
var modal = new DiscordInteractionModalBuilder().WithTitle(this.GetString(this.t.Commands.Common.Prompts.SelectADateTime)).WithCustomId(Guid.NewGuid().ToString());
_ = modal.AddTextComponent(new DiscordTextComponent(TextComponentStyle.Small, "minute", this.GetString(this.t.Commands.Common.Prompts.DateTimeMinute), this.GetString(this.t.Commands.Common.Prompts.DateTimeMinute), 1, 2, true, $"{userTime.Minute}"));
_ = modal.AddTextComponent(new DiscordTextComponent(TextComponentStyle.Small, "hour", this.GetString(this.t.Commands.Common.Prompts.DateTimeHour), this.GetString(this.t.Commands.Common.Prompts.DateTimeHour), 1, 2, true, $"{userTime.Hour}"));
_ = modal.AddTextComponent(new DiscordTextComponent(TextComponentStyle.Small, "day", this.GetString(this.t.Commands.Common.Prompts.DateTimeDay), this.GetString(this.t.Commands.Common.Prompts.DateTimeDay), 1, 2, true, $"{userTime.Day}"));
_ = modal.AddTextComponent(new DiscordTextComponent(TextComponentStyle.Small, "month", this.GetString(this.t.Commands.Common.Prompts.DateTimeMonth), this.GetString(this.t.Commands.Common.Prompts.DateTimeMonth), 1, 2, true, $"{userTime.Month}"));
_ = modal.AddTextComponent(new DiscordTextComponent(TextComponentStyle.Small, "year", this.GetString(this.t.Commands.Common.Prompts.DateTimeYear), this.GetString(this.t.Commands.Common.Prompts.DateTimeYear), 1, 4, true, $"{userTime.Year}"));
var ModalResult = await this.PromptModalWithRetry(modalInteraction, modal, null, false, timeOutOverride.Value.Subtract(timeOut.Elapsed), modalInteraction != null);
if (ModalResult.Errored)
{
await UpdateMessage();
return;
}
InteractionCreateEventArgs Response = ModalResult.Result;
DateTime dateTime;
try
{
if ((Response.Interaction.Data.Components.Any(x => x.CustomId == "hour") && !Response.Interaction.Data.Components.First(x => x.CustomId == "hour").Value.IsDigitsOnly()) ||
(Response.Interaction.Data.Components.Any(x => x.CustomId == "minute") && !Response.Interaction.Data.Components.First(x => x.CustomId == "minute").Value.IsDigitsOnly()) ||
(Response.Interaction.Data.Components.Any(x => x.CustomId == "day") && !Response.Interaction.Data.Components.First(x => x.CustomId == "day").Value.IsDigitsOnly()) ||
(Response.Interaction.Data.Components.Any(x => x.CustomId == "month") && !Response.Interaction.Data.Components.First(x => x.CustomId == "month").Value.IsDigitsOnly()) ||
(Response.Interaction.Data.Components.Any(x => x.CustomId == "year") && !Response.Interaction.Data.Components.First(x => x.CustomId == "year").Value.IsDigitsOnly()))
throw new ArgumentException("Invalid date time");
var hour = Convert.ToInt32(Response.Interaction.GetModalValueByCustomId("hour"));
var minute = Convert.ToInt32(Response.Interaction.GetModalValueByCustomId("minute"));
var day = Convert.ToInt32(Response.Interaction.GetModalValueByCustomId("day"));
var month = Convert.ToInt32(Response.Interaction.GetModalValueByCustomId("month"));
var year = Convert.ToInt32(Response.Interaction.GetModalValueByCustomId("year"));
dateTime = TimeZoneInfo.ConvertTimeToUtc(new DateTime(year, month, day, hour, minute, 0, DateTimeKind.Unspecified), userTimezone);
}
catch (Exception)
{
await UpdateMessage();
return;
}
currentSelectedTime = dateTime;
}
else
{ return; }
await UpdateMessage();
}
}).Add(this.ctx.Bot, this.ctx);
}
this.ctx.Client.ComponentInteractionCreated += Interaction;
while (!Finished && !Cancelled && timeOut.ElapsedMilliseconds < timeOutOverride.Value.TotalMilliseconds)
await Task.Delay(1000);
this.ctx.Client.ComponentInteractionCreated -= Interaction;
if (!Finished && !Cancelled && timeOut.ElapsedMilliseconds < timeOutOverride.Value.TotalMilliseconds)
return new InteractionResult<DateTime>(new TimedOutException());
if (Cancelled)
return new InteractionResult<DateTime>(new CancelException());
if (ResetToOriginalEmbed)
_ = await this.RespondOrEdit(new DiscordMessageBuilder().AddEmbeds(originalEmbed));
return new InteractionResult<DateTime>(currentSelectedTime);
}
#endregion
public async Task<(Stream stream, int fileSize)> PromptForFileUpload(TimeSpan? timeOutOverride = null)
{
timeOutOverride ??= TimeSpan.FromMinutes(15);
if (this.ctx.DbUser.PendingUserUpload is not null)
{
if (this.ctx.DbUser.PendingUserUpload.TimeOut.GetTotalSecondsUntil() > 0 && !this.ctx.DbUser.PendingUserUpload.InteractionHandled)
{
_ = await this.RespondOrEdit(new DiscordMessageBuilder().AddEmbed(new DiscordEmbedBuilder
{
Description = $"`An upload interaction is already taking place. Please finish it beforehand.`",
}.AsError(this.ctx)));
throw new AlreadyAppliedException("");
}
this.ctx.DbUser.PendingUserUpload = null;
}
this.ctx.DbUser.PendingUserUpload = new UserUpload
{
TimeOut = DateTime.UtcNow.Add(timeOutOverride.Value)
};
while (this.ctx.DbUser.PendingUserUpload is not null && !this.ctx.DbUser.PendingUserUpload.InteractionHandled && this.ctx.DbUser.PendingUserUpload.TimeOut.GetTotalSecondsUntil() > 0)
{
await Task.Delay(500);
}
if (!this.ctx.DbUser.PendingUserUpload?.InteractionHandled ?? true)
throw new ArgumentException("");
var size = this.ctx.DbUser.PendingUserUpload.FileSize;
var stream = this.ctx.DbUser.PendingUserUpload.UploadedData;
this.ctx.DbUser.PendingUserUpload = null;
return (stream, size);
}
#region FinishInteraction
public void ModifyToTimedOut(bool Delete = false)
{
_ = this.RespondOrEdit(new DiscordMessageBuilder().AddEmbed(new DiscordEmbedBuilder(this.ctx.ResponseMessage.Embeds[0]).WithFooter(this.ctx.ResponseMessage.Embeds[0]?.Footer?.Text + $" • {this.GetString(this.t.Commands.Common.InteractionTimeout)}").WithColor(DiscordColor.Gray)));
if (Delete)
_ = Task.Delay(5000).ContinueWith(_ =>
{
if (!this.ctx.ResponseMessage?.Flags.Value.HasMessageFlag(MessageFlags.Ephemeral) ?? false)
_ = this.ctx.ResponseMessage.DeleteAsync();
});
}
public void DeleteOrInvalidate()
{
switch (this.ctx.CommandType)
{
case Enums.CommandType.ContextMenu:
{
_ = this.ctx.OriginalContextMenuContext.DeleteResponseAsync();
break;
}
case Enums.CommandType.Event:
{
_ = this.ctx.OriginalComponentInteractionCreateEventArgs.Interaction.DeleteOriginalResponseAsync();
break;
}
case Enums.CommandType.ApplicationCommand:
{
_ = this.ctx.OriginalInteractionContext.DeleteResponseAsync();
break;
}
default:
{
_ = this.ctx.ResponseMessage?.DeleteAsync();
break;
}
}
}
#endregion
#region Checks
public async Task<bool> CheckVoiceState()
{
if (this.ctx.Member.VoiceState is null)
{
this.SendVoiceStateError();
return false;
}
return true;
}
public async Task<bool> CheckMaintenance()
{
if (!this.ctx.User.IsMaintenance(this.ctx.Bot.status))
{
this.SendMaintenanceError();
return false;
}
return true;
}
public async Task<bool> CheckBotOwner()
{
if (!this.ctx.User.IsMaintenance(this.ctx.Bot.status))
{
this.SendBotOwnerError();
return false;
}
return true;
}
public async Task<bool> CheckAdmin()
{
if (!this.ctx.Member.IsAdmin(this.ctx.Bot.status))
{
this.SendAdminError();
return false;
}
return true;
}
public async Task<bool> CheckPermissions(Permissions perms)
{
if (!this.ctx.Member.Permissions.HasPermission(perms))
{
this.SendPermissionError(perms);
return false;
}
return true;
}
public async Task<bool> CheckOwnPermissions(Permissions perms)
{
if (!this.ctx.CurrentMember.Permissions.HasPermission(perms))
{
this.SendOwnPermissionError(perms);
return false;
}
return true;
}
public async Task<bool> CheckSource(Enums.CommandType commandType)
{
if (this.ctx.CommandType != commandType)
{
this.SendSourceError(commandType);
return false;
}
return true;
}
#endregion
#region ErrorTemplates
public void SendDisabledCommandError(string disabledCommand)
=> _ = this.RespondOrEdit(new DiscordEmbedBuilder()
{
Description = this.GetString(this.t.Commands.Common.Errors.CommandDisabled, true, new TVar("Command", disabledCommand))
}.AsError(this.ctx));
public void SendNoMemberError()
=> _ = this.RespondOrEdit(new DiscordEmbedBuilder()
{
Description = this.GetString(this.t.Commands.Common.Errors.NoMember)
}.AsError(this.ctx));
public void SendMaintenanceError()
=> _ = this.RespondOrEdit(new DiscordEmbedBuilder()
{
Description = this.GetString(this.t.Commands.Common.Errors.Generic).Build(true, new TVar("Required", $"{this.ctx.CurrentUser.GetUsername()} Staff"))
}.AsError(this.ctx));
public void SendBotOwnerError()
=> _ = this.RespondOrEdit(new DiscordEmbedBuilder()
{
Description = this.GetString(this.t.Commands.Common.Errors.Generic).Build(true, new TVar("Required", $"<@{this.ctx.Bot.status.TeamOwner}>", false)),
}.AsError(this.ctx));
public void SendAdminError()
=> _ = this.RespondOrEdit(new DiscordEmbedBuilder()
{
Description = this.GetString(this.t.Commands.Common.Errors.Generic).Build(true, new TVar("Required", "Administrator")),
}.AsError(this.ctx));
public void SendPermissionError(Permissions perms)
=> _ = this.RespondOrEdit(new DiscordEmbedBuilder()
{
Description = this.GetString(this.t.Commands.Common.Errors.Generic).Build(true, new TVar("Required", perms.ToTranslatedPermissionString(this.ctx.DbUser, this.ctx.Bot))),
}.AsError(this.ctx));
public void SendVoiceStateError()
=> _ = this.RespondOrEdit(new DiscordMessageBuilder().AddEmbed(new DiscordEmbedBuilder
{
Description = this.GetString(this.t.Commands.Common.Errors.VoiceChannel).Build(true),
}.AsError(this.ctx)));
public void SendUserBanError(BanDetails entry)
=> _ = this.RespondOrEdit(new DiscordMessageBuilder().AddEmbed(new DiscordEmbedBuilder
{
Description = this.t.Commands.Common.Errors.UserBan.t["en"].Build(true, new TVar("Reason", entry.Reason)),
}.AsError(this.ctx)));
public void SendGuildBanError(BanDetails entry)
=> _ = this.RespondOrEdit(new DiscordMessageBuilder().AddEmbed(new DiscordEmbedBuilder
{
Description = this.GetString(this.t.Commands.Common.Errors.GuildBan, true, new TVar("Reason", entry.Reason)),
}.AsError(this.ctx)));
public void SendSourceError(Enums.CommandType commandType)
=> _ = commandType switch
{
Enums.CommandType.ApplicationCommand => this.RespondOrEdit(new DiscordEmbedBuilder()
{
Description = this.GetString(this.t.Commands.Common.Errors.ExclusiveApp).Build(true),
}.AsError(this.ctx)),
Enums.CommandType.PrefixCommand => this.RespondOrEdit(new DiscordEmbedBuilder()
{
Description = this.GetString(this.t.Commands.Common.Errors.ExclusivePrefix).Build(true)
}.AsError(this.ctx)),
_ => throw new ArgumentException("Invalid Source defined."),
};
public void SendDataError()
=> _ = this.RespondOrEdit(new DiscordMessageBuilder().AddEmbed(new DiscordEmbedBuilder
{
Description = this.GetString(this.t.Commands.Common.Errors.Data, true, new TVar("Command", $"{this.ctx.Prefix}data delete")),
}.AsError(this.ctx)));
public void SendDmError()
=> _ = this.RespondOrEdit(new DiscordMessageBuilder().AddEmbed(new DiscordEmbedBuilder
{
Description = $"📩 {this.GetString(this.t.Commands.Common.Errors.DirectMessage, true)}",
ImageUrl = (this.ctx.User.Presence.ClientStatus.Mobile.HasValue ? "https://cdn.discordapp.com/attachments/1005430437952356423/1144961395515998238/34rhz83ghtzu3ght.gif" : "https://cdn.discordapp.com/attachments/1005430437952356423/1144964670197862400/et2grtzu2ghrzi52.gif")
}.AsError(this.ctx)));
public void SendDmRedirect()
=> _ = this.RespondOrEdit(new DiscordMessageBuilder().AddEmbed(new DiscordEmbedBuilder
{
Description = $"📩 {this.GetString(this.t.Commands.Common.DirectMessageRedirect, true)}",
}.AsSuccess(this.ctx)));
public void SendOwnPermissionError(Permissions perms)
{
if (perms is Permissions.AccessChannels or Permissions.SendMessages or Permissions.EmbedLinks)
return;
_ = this.RespondOrEdit(new DiscordEmbedBuilder()
{
Description = this.GetString(this.t.Commands.Common.Errors.BotPermissions, true, new TVar("Required", perms.ToTranslatedPermissionString(this.ctx.DbUser, this.ctx.Bot)))
}.AsError(this.ctx));
}
public void SendSyntaxError()
{
if (this.ctx.CommandType != Enums.CommandType.PrefixCommand)
throw new ArgumentException("Syntax Error can only be generated for Prefix Commands.");
var ctx = this.ctx.OriginalCommandContext;
var embed = new DiscordEmbedBuilder
{
Description = $"**`{ctx.Prefix}{ctx.Command.Name}{(ctx.RawArgumentString != "" ? $" {ctx.RawArgumentString.SanitizeForCode().Replace("\\", "")}" : "")}` is not a valid way of using this command.**\nUse it like this instead: `{ctx.Prefix}{ctx.Command.GenerateUsage()}`\n\nArguments wrapped in `[]` are optional while arguments wrapped in `<>` are required.\n**Do not include the brackets when using commands, they're merely an indicator for requirement.**",
}.AsError(this.ctx);
_ = this.RespondOrEdit(new DiscordMessageBuilder().AddEmbed(embed).WithContent(this.ctx.User.Mention));
}
#endregion
}