refactor: Initial release
This commit is contained in:
commit
9505750e29
447 changed files with 41522 additions and 0 deletions
92
ProjectMakoto/Commands/Utility/AvatarCommand.cs
Normal file
92
ProjectMakoto/Commands/Utility/AvatarCommand.cs
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
// 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
|
||||
|
||||
namespace ProjectMakoto.Commands;
|
||||
internal sealed class AvatarCommand : BaseCommand
|
||||
{
|
||||
public override Task ExecuteCommand(SharedCommandContext ctx, Dictionary<string, object> arguments)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
var victim = (DiscordUser)arguments["user"];
|
||||
|
||||
if (await ctx.DbUser.Cooldown.WaitForModerate(ctx))
|
||||
return;
|
||||
|
||||
victim ??= ctx.User;
|
||||
|
||||
victim = await victim.GetFromApiAsync();
|
||||
|
||||
var embed = new DiscordEmbedBuilder
|
||||
{
|
||||
ImageUrl = victim.AvatarUrl,
|
||||
}.AsInfo(ctx, this.GetString(this.t.Commands.Utility.Avatar.Avatar, false, new TVar("User", victim.GetUsernameWithIdentifier())));
|
||||
|
||||
DiscordMember member = null;
|
||||
|
||||
try
|
||||
{ member = await victim.ConvertToMember(ctx.Guild); }
|
||||
catch { }
|
||||
|
||||
var ServerProfilePictureButton = new DiscordButtonComponent(ButtonStyle.Secondary, "ShowServer", this.GetString(this.t.Commands.Utility.Avatar.ShowServerProfile), (string.IsNullOrWhiteSpace(member?.GuildAvatarHash)), new DiscordComponentEmoji(DiscordEmoji.FromUnicode("🖥")));
|
||||
var ProfilePictureButton = new DiscordButtonComponent(ButtonStyle.Secondary, "ShowProfile", this.GetString(this.t.Commands.Utility.Avatar.ShowUserProfile), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("👤")));
|
||||
|
||||
var builder = new DiscordMessageBuilder().WithEmbed(embed).AddComponents(ServerProfilePictureButton);
|
||||
|
||||
var msg = await this.RespondOrEdit(builder);
|
||||
|
||||
CancellationTokenSource cancellationTokenSource = new();
|
||||
|
||||
ctx.Client.ComponentInteractionCreated += RunInteraction;
|
||||
|
||||
_ = Task.Delay(60000, cancellationTokenSource.Token).ContinueWith(x =>
|
||||
{
|
||||
if (x.IsCompletedSuccessfully)
|
||||
{
|
||||
ctx.Client.ComponentInteractionCreated -= RunInteraction;
|
||||
this.ModifyToTimedOut(true);
|
||||
}
|
||||
});
|
||||
|
||||
async Task RunInteraction(DiscordClient s, ComponentInteractionCreateEventArgs e)
|
||||
{
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
if (e.Message?.Id == msg.Id && e.User.Id == ctx.User.Id)
|
||||
{
|
||||
cancellationTokenSource.Cancel();
|
||||
cancellationTokenSource = new();
|
||||
|
||||
_ = Task.Delay(60000, cancellationTokenSource.Token).ContinueWith(x =>
|
||||
{
|
||||
if (x.IsCompletedSuccessfully)
|
||||
{
|
||||
ctx.Client.ComponentInteractionCreated -= RunInteraction;
|
||||
this.ModifyToTimedOut(true);
|
||||
}
|
||||
});
|
||||
|
||||
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
|
||||
|
||||
if (e.GetCustomId() == ServerProfilePictureButton.CustomId)
|
||||
{
|
||||
embed.ImageUrl = member.GuildAvatarUrl;
|
||||
_ = this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(embed).AddComponents(ProfilePictureButton));
|
||||
}
|
||||
else if (e.GetCustomId() == ProfilePictureButton.CustomId)
|
||||
{
|
||||
embed.ImageUrl = member.AvatarUrl;
|
||||
_ = this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(embed).AddComponents(ServerProfilePictureButton));
|
||||
}
|
||||
}
|
||||
}).Add(ctx.Bot, ctx);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
37
ProjectMakoto/Commands/Utility/BannerCommand.cs
Normal file
37
ProjectMakoto/Commands/Utility/BannerCommand.cs
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
// 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
|
||||
|
||||
namespace ProjectMakoto.Commands;
|
||||
internal sealed class BannerCommand : BaseCommand
|
||||
{
|
||||
public override Task ExecuteCommand(SharedCommandContext ctx, Dictionary<string, object> arguments)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
var victim = (DiscordUser)arguments["user"];
|
||||
|
||||
if (await ctx.DbUser.Cooldown.WaitForModerate(ctx))
|
||||
return;
|
||||
|
||||
victim ??= ctx.User;
|
||||
|
||||
victim = await victim.GetFromApiAsync();
|
||||
|
||||
var embed = new DiscordEmbedBuilder
|
||||
{
|
||||
ImageUrl = victim.BannerUrl,
|
||||
Description = victim.BannerUrl.IsNullOrWhiteSpace() ? this.GetString(this.t.Commands.Utility.Banner.NoBanner, true) : ""
|
||||
}.AsInfo(ctx, this.GetString(this.t.Commands.Utility.Banner.Banner, false, new TVar("User", victim.GetUsernameWithIdentifier())));
|
||||
|
||||
var builder = new DiscordMessageBuilder().WithEmbed(embed);
|
||||
|
||||
_ = await this.RespondOrEdit(builder);
|
||||
});
|
||||
}
|
||||
}
|
||||
48
ProjectMakoto/Commands/Utility/CreditsCommand.cs
Normal file
48
ProjectMakoto/Commands/Utility/CreditsCommand.cs
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
// 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
|
||||
|
||||
namespace ProjectMakoto.Commands;
|
||||
|
||||
internal sealed class CreditsCommand : BaseCommand
|
||||
{
|
||||
public override Task ExecuteCommand(SharedCommandContext ctx, Dictionary<string, object> arguments)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
if (await ctx.DbUser.Cooldown.WaitForHeavy(ctx, true))
|
||||
return;
|
||||
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(this.t.Commands.Utility.Credits.Fetching, true)
|
||||
}.AsLoading(ctx));
|
||||
|
||||
var contributors = await ctx.Bot.GithubClient.Repository.GetAllContributors(ctx.Bot.status.LoadedConfig.Secrets.Github.Username, ctx.Bot.status.LoadedConfig.Secrets.Github.Repository);
|
||||
var contributorsdcs = await ctx.Bot.GithubClient.Repository.GetAllContributors("Aiko-IT-Systems", "DisCatSharp");
|
||||
|
||||
List<DiscordUser> userlist = new();
|
||||
|
||||
foreach (var b in ctx.Bot.status.TeamMembers.Reverse<ulong>())
|
||||
userlist.Add(await ctx.Client.GetUserAsync(b));
|
||||
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(this.t.Commands.Utility.Credits.Credits, false, false,
|
||||
new TVar("BotName", ctx.CurrentUser.GetUsername(), false),
|
||||
new TVar("Developer", "<@411950662662881290> ([`TheXorog`](https://github.com/TheXorog))", false),
|
||||
new TVar("DiscordStaffList", string.Join(", ", userlist.Select(x => $"{x.Mention} [`{x.GetUsernameWithIdentifier()}`]({x.ProfileUrl})")), false),
|
||||
new TVar("GitHubContList", string.Join("\n", contributors.Where(x => !x.Login.Contains("[bot]") && x.Login != "TheXorog").OrderByDescending(x => x.Contributions).Select(x => $"• [`{x.Login}`]({x.HtmlUrl})")), false),
|
||||
new TVar("Library", "[`DisCatSharp`](https://github.com/Aiko-IT-Systems/DisCatSharp)", false),
|
||||
new TVar("LibraryContList", string.Join(", ", contributorsdcs.Take(10).Where(x => !x.Login.Contains("[bot]")).OrderByDescending(x => x.Contributions).Select(x => $"[`{x.Login}`]({x.HtmlUrl})")), false),
|
||||
new TVar("LibraryContCount", $"[{contributorsdcs.Count - 10}](https://github.com/Aiko-IT-Systems/DisCatSharp/graphs/contributors)", false),
|
||||
new TVar("PhishingListRepos", $"[`nikolaischunk`](https://github.com/nikolaischunk), [`DevSpen`](https://github.com/DevSpen), [`PoorPocketsMcNewHold`](https://github.com/PoorPocketsMcNewHold), [`sk-cat`](https://github.com/sk-cat) & [`Junortiz`](https://github.com/Junortiz)", false))
|
||||
}.AsInfo(ctx));
|
||||
});
|
||||
}
|
||||
}
|
||||
166
ProjectMakoto/Commands/Utility/Data/DeleteCommand.cs
Normal file
166
ProjectMakoto/Commands/Utility/Data/DeleteCommand.cs
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
// 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
|
||||
|
||||
namespace ProjectMakoto.Commands.Data;
|
||||
|
||||
internal sealed class DeleteCommand : BaseCommand
|
||||
{
|
||||
public override Task ExecuteCommand(SharedCommandContext ctx, Dictionary<string, object> arguments)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
if (await ctx.DbUser.Cooldown.WaitForHeavy(ctx, true))
|
||||
return;
|
||||
|
||||
var Yes = new DiscordButtonComponent(ButtonStyle.Success, Guid.NewGuid().ToString(), this.GetString(this.t.Common.Yes), false, new DiscordComponentEmoji(true.ToEmote(ctx.Bot)));
|
||||
var No = new DiscordButtonComponent(ButtonStyle.Danger, Guid.NewGuid().ToString(), this.GetString(this.t.Common.No), false, new DiscordComponentEmoji(false.ToEmote(ctx.Bot)));
|
||||
|
||||
if (ctx.Bot.objectedUsers.Contains(ctx.User.Id))
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(this.t.Commands.Utility.Data.Object.ProfileAlreadyDeleted, true)
|
||||
}.AsAwaitingInput(ctx)).AddComponents(new List<DiscordComponent> { Yes, No }));
|
||||
|
||||
var Menu1 = await ctx.WaitForButtonAsync();
|
||||
|
||||
if (Menu1.TimedOut)
|
||||
{
|
||||
this.ModifyToTimedOut();
|
||||
return;
|
||||
}
|
||||
|
||||
_ = Menu1.Result.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
|
||||
|
||||
if (Menu1.GetCustomId() == Yes.CustomId)
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(this.t.Commands.Utility.Data.Object.EnablingDataProcessing, true)
|
||||
}.AsLoading(ctx));
|
||||
|
||||
try
|
||||
{
|
||||
_ = ctx.Bot.objectedUsers.Remove(ctx.User.Id);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "An exception occurred while trying to remove a user from the objection list");
|
||||
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(this.t.Commands.Utility.Data.Object.EnablingDataProcessingError, true)
|
||||
}.AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(this.t.Commands.Utility.Data.Object.EnablingDataProcessingSuccess, true)
|
||||
}.AsSuccess(ctx));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.DeleteOrInvalidate();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.DbUser.Data.DeletionRequested)
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(this.t.Commands.Utility.Data.Object.DeletionAlreadyScheduled, true,
|
||||
new TVar("RequestTimestamp", ctx.DbUser.Data.DeletionRequestDate.AddDays(-14).ToTimestamp()),
|
||||
new TVar("ScheduleTimestamp", ctx.DbUser.Data.DeletionRequestDate.ToTimestamp()))
|
||||
}.AsAwaitingInput(ctx)).AddComponents(new List<DiscordComponent> { Yes, No }));
|
||||
|
||||
var Menu1 = await ctx.WaitForButtonAsync();
|
||||
|
||||
if (Menu1.TimedOut)
|
||||
{
|
||||
this.ModifyToTimedOut();
|
||||
return;
|
||||
}
|
||||
|
||||
_ = Menu1.Result.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
|
||||
|
||||
if (Menu1.GetCustomId() == Yes.CustomId)
|
||||
{
|
||||
ctx.DbUser.Data.DeletionRequested = false;
|
||||
ctx.DbUser.Data.DeletionRequestDate = DateTime.MinValue;
|
||||
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(this.t.Commands.Utility.Data.Object.DeletionScheduleReversed, true)
|
||||
}.AsSuccess(ctx));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.DeleteOrInvalidate();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(this.t.Commands.Utility.Data.Object.ObjectionDisclaimer, true, true)
|
||||
}.AsAwaitingInput(ctx)).AddComponents(new List<DiscordComponent> { Yes, No }));
|
||||
|
||||
var Menu = await ctx.WaitForButtonAsync();
|
||||
|
||||
if (Menu.TimedOut)
|
||||
{
|
||||
this.ModifyToTimedOut();
|
||||
return;
|
||||
}
|
||||
|
||||
_ = Menu.Result.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
|
||||
|
||||
if (Menu.GetCustomId() == Yes.CustomId)
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = $"**{this.GetString(this.t.Commands.Utility.Data.Object.SecondaryConfirm, true)}**"
|
||||
}.AsAwaitingInput(ctx)).AddComponents(new List<DiscordComponent> { No, Yes }));
|
||||
|
||||
Menu = await ctx.WaitForButtonAsync();
|
||||
|
||||
if (Menu.TimedOut)
|
||||
{
|
||||
this.ModifyToTimedOut();
|
||||
return;
|
||||
}
|
||||
|
||||
_ = Menu.Result.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
|
||||
|
||||
if (Menu.GetCustomId() == Yes.CustomId)
|
||||
{
|
||||
ctx.DbUser.Data.DeletionRequestDate = DateTime.UtcNow.AddDays(14);
|
||||
ctx.DbUser.Data.DeletionRequested = true;
|
||||
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(this.t.Commands.Utility.Data.Object.ProfileDeletionScheduled, true)
|
||||
}.AsSuccess(ctx));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.DeleteOrInvalidate();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.DeleteOrInvalidate();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
65
ProjectMakoto/Commands/Utility/Data/InfoCommand.cs
Normal file
65
ProjectMakoto/Commands/Utility/Data/InfoCommand.cs
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
// 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
|
||||
|
||||
namespace ProjectMakoto.Commands.Data;
|
||||
|
||||
internal sealed class InfoCommand : BaseCommand
|
||||
{
|
||||
public override Task ExecuteCommand(SharedCommandContext ctx, Dictionary<string, object> arguments)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
if (await ctx.DbUser.Cooldown.WaitForHeavy(ctx, true))
|
||||
return;
|
||||
|
||||
if (ctx.Bot.RawFetchedPrivacyPolicy.IsNullOrWhiteSpace())
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(this.t.Commands.Utility.Data.Policy.NoPolicy, true, new TVar("Bot", ctx.CurrentUser.GetUsername())),
|
||||
}.AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
var RawPolicy = ctx.Bot.RawFetchedPrivacyPolicy.Replace("#", "");
|
||||
|
||||
var PolicyStrings = RawPolicy.ReplaceLineEndings("\n").Split("\n\n").ToList();
|
||||
|
||||
var Title = "";
|
||||
List<DiscordEmbed> embeds = new();
|
||||
|
||||
for (var i = 0; i < PolicyStrings.Count; i++)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
Title = PolicyStrings[i];
|
||||
continue;
|
||||
}
|
||||
|
||||
embeds.Add(new DiscordEmbedBuilder
|
||||
{
|
||||
Title = (i == 1 ? Title : ""),
|
||||
Description = PolicyStrings[i]
|
||||
});
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
foreach (var b in embeds)
|
||||
_ = await ctx.User.SendMessageAsync(b);
|
||||
|
||||
this.SendDmRedirect();
|
||||
}
|
||||
catch (DisCatSharp.Exceptions.UnauthorizedException)
|
||||
{
|
||||
this.SendDmError();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
86
ProjectMakoto/Commands/Utility/Data/RequestCommand.cs
Normal file
86
ProjectMakoto/Commands/Utility/Data/RequestCommand.cs
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
// 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
|
||||
|
||||
namespace ProjectMakoto.Commands.Data;
|
||||
|
||||
internal sealed class RequestCommand : BaseCommand
|
||||
{
|
||||
public override Task ExecuteCommand(SharedCommandContext ctx, Dictionary<string, object> arguments)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
if (await ctx.DbUser.Cooldown.WaitForHeavy(ctx, true))
|
||||
return;
|
||||
|
||||
if (ctx.DbUser.Data.LastDataRequest.GetTimespanSince() < TimeSpan.FromDays(14))
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(this.t.Commands.Utility.Data.Request.TimeError, true,
|
||||
new TVar("RequestTimestamp", ctx.DbUser.Data.LastDataRequest.ToTimestamp(TimestampFormat.ShortDateTime)),
|
||||
new TVar("WaitTimestamp", ctx.DbUser.Data.LastDataRequest.AddDays(14).ToTimestamp(TimestampFormat.ShortDateTime)))
|
||||
}.AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(this.t.Commands.Utility.Data.Request.Fetching, true)
|
||||
}.AsLoading(ctx));
|
||||
|
||||
RequestData requestData = new();
|
||||
|
||||
if (ctx.Bot.Users.ContainsKey(ctx.User.Id))
|
||||
{
|
||||
requestData.User = ctx.DbUser;
|
||||
}
|
||||
|
||||
foreach (var guild in ctx.Bot.Guilds)
|
||||
{
|
||||
if (guild.Value.Members.TryGetValue(ctx.User.Id, out var member))
|
||||
{
|
||||
requestData.GuildData.Add(guild.Key, member);
|
||||
}
|
||||
}
|
||||
|
||||
Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(requestData, Formatting.Indented)));
|
||||
|
||||
switch (ctx.CommandType)
|
||||
{
|
||||
case Enums.CommandType.ApplicationCommand:
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(this.t.Commands.Utility.Data.Request.Confirm, true)
|
||||
}.AsSuccess(ctx)).WithFile("userdata.json", stream));
|
||||
ctx.DbUser.Data.LastDataRequest = DateTime.UtcNow;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
try
|
||||
{
|
||||
_ = await ctx.User.SendMessageAsync(new DiscordMessageBuilder().WithEmbed(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(this.t.Commands.Utility.Data.Request.Confirm, true)
|
||||
}.AsSuccess(ctx)).WithFile("userdata.json", stream));
|
||||
ctx.DbUser.Data.LastDataRequest = DateTime.UtcNow;
|
||||
|
||||
this.SendDmRedirect();
|
||||
}
|
||||
catch (DisCatSharp.Exceptions.UnauthorizedException)
|
||||
{
|
||||
this.SendDmError();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
530
ProjectMakoto/Commands/Utility/EmojiStealerCommand.cs
Normal file
530
ProjectMakoto/Commands/Utility/EmojiStealerCommand.cs
Normal file
|
|
@ -0,0 +1,530 @@
|
|||
// 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
|
||||
|
||||
namespace ProjectMakoto.Commands;
|
||||
|
||||
internal sealed class EmojiStealerCommand : BaseCommand
|
||||
{
|
||||
public override Task ExecuteCommand(SharedCommandContext ctx, Dictionary<string, object> arguments)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
DiscordMessage bMessage;
|
||||
|
||||
if (arguments?.ContainsKey("message") ?? false)
|
||||
{
|
||||
bMessage = (DiscordMessage)arguments["message"];
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (ctx.CommandType)
|
||||
{
|
||||
case Enums.CommandType.PrefixCommand:
|
||||
{
|
||||
if (ctx.OriginalCommandContext.Message.ReferencedMessage is not null)
|
||||
{
|
||||
bMessage = ctx.OriginalCommandContext.Message.ReferencedMessage;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.SendSyntaxError();
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new ArgumentException("Message expected");
|
||||
}
|
||||
}
|
||||
|
||||
if (await ctx.DbUser.Cooldown.WaitForModerate(ctx))
|
||||
return;
|
||||
|
||||
HttpClient client = new();
|
||||
|
||||
var embed = new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(this.t.Commands.Utility.EmojiStealer.DownloadingPre, true),
|
||||
}.AsLoading(ctx);
|
||||
_ = await this.RespondOrEdit(embed);
|
||||
|
||||
Dictionary<ulong, EmojiEntry> SanitizedEmoteList = new();
|
||||
MemoryStream zipFileStream = new();
|
||||
var FinishedInteraction = false;
|
||||
|
||||
var Emotes = bMessage.Content.GetEmotes();
|
||||
|
||||
foreach (var b in Emotes)
|
||||
SanitizedEmoteList.Add(b.Item1, new EmojiEntry
|
||||
{
|
||||
Name = b.Item2,
|
||||
Animated = b.Item3,
|
||||
EntryType = EmojiType.EMOJI
|
||||
});
|
||||
|
||||
if (Emotes.Count == 0 && (bMessage.Stickers is null || bMessage.Stickers.Count == 0))
|
||||
{
|
||||
embed.Description = this.GetString(this.t.Commands.Utility.EmojiStealer.NoEmojis, true);
|
||||
_ = await this.RespondOrEdit(embed.AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
var guid = Guid.NewGuid().ToString().MakeValidFileName();
|
||||
|
||||
try
|
||||
{
|
||||
if (SanitizedEmoteList.Count > 0)
|
||||
{
|
||||
embed.Description = this.GetString(this.t.Commands.Utility.EmojiStealer.DownloadingEmojis, true, new TVar("Count", SanitizedEmoteList.Count));
|
||||
_ = await this.RespondOrEdit(embed);
|
||||
|
||||
foreach (var b in SanitizedEmoteList.ToList())
|
||||
{
|
||||
try
|
||||
{
|
||||
var EmoteStream = await client.GetStreamAsync($"https://cdn.discordapp.com/emojis/{b.Key}.{(b.Value.Animated ? "gif" : "png")}");
|
||||
|
||||
var NameExists = "";
|
||||
var NameExistsInt = 1;
|
||||
|
||||
var Name = $"{b.Value.Name}{NameExists}.{(b.Value.Animated ? "gif" : "png")}".MakeValidFileName('_');
|
||||
|
||||
while (SanitizedEmoteList.Any(x => x.Value.Data.Name == Name))
|
||||
{
|
||||
NameExistsInt++;
|
||||
NameExists = $" ({NameExistsInt})";
|
||||
|
||||
Name = $"{b.Value.Name}{NameExists}.{(b.Value.Animated ? "gif" : "png")}".MakeValidFileName('_');
|
||||
}
|
||||
|
||||
b.Value.Data.Name = Name;
|
||||
EmoteStream.CopyTo(b.Value.Data.Stream);
|
||||
b.Value.Data.Stream.Position = 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Failed to download an emote");
|
||||
|
||||
_ = SanitizedEmoteList.Remove(b.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bMessage.Stickers.Count > 0)
|
||||
{
|
||||
embed.Description = this.GetString(this.t.Commands.Utility.EmojiStealer.DownloadingStickers, true, new TVar("Count", bMessage.Stickers.GroupBy(x => x.Url).Select(x => x.First()).Count()));
|
||||
_ = await this.RespondOrEdit(embed);
|
||||
|
||||
foreach (var b in bMessage.Stickers.GroupBy(x => x.Url).Select(x => x.First()))
|
||||
{
|
||||
var newEntry = new EmojiEntry
|
||||
{
|
||||
Animated = false,
|
||||
Name = b.Name,
|
||||
Description = b.Description,
|
||||
Emoji = "🤖".UnicodeToEmoji(),
|
||||
StickerFormat = b.FormatType,
|
||||
EntryType = EmojiType.STICKER
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
var StickerStream = await client.GetStreamAsync(b.Url);
|
||||
|
||||
var NameExists = "";
|
||||
var NameExistsInt = 1;
|
||||
|
||||
var Name = $"{b.Name}{NameExists}.png".MakeValidFileName('_');
|
||||
|
||||
while (SanitizedEmoteList.Any(x => x.Value.Data.Name == Name))
|
||||
{
|
||||
NameExistsInt++;
|
||||
NameExists = $" ({NameExistsInt})";
|
||||
|
||||
Name = $"{newEntry.Name}{NameExists}.png".MakeValidFileName('_');
|
||||
}
|
||||
|
||||
newEntry.Data.Name = Name;
|
||||
StickerStream.CopyTo(newEntry.Data.Stream);
|
||||
newEntry.Data.Stream.Position = 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Failed to download an emote");
|
||||
|
||||
_ = SanitizedEmoteList.Remove(b.Id);
|
||||
}
|
||||
|
||||
SanitizedEmoteList.Add(b.Id, newEntry);
|
||||
}
|
||||
}
|
||||
|
||||
if (SanitizedEmoteList.Count == 0)
|
||||
{
|
||||
embed.Description = this.GetString(this.t.Commands.Utility.EmojiStealer.NoSuccessfulDownload, true);
|
||||
_ = await this.RespondOrEdit(embed.AsError(ctx));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var emojiText = "";
|
||||
|
||||
if (SanitizedEmoteList.Any(x => x.Value.EntryType == EmojiType.EMOJI))
|
||||
emojiText += this.GetString(this.t.Commands.Utility.EmojiStealer.Emoji);
|
||||
|
||||
if (SanitizedEmoteList.Any(x => x.Value.EntryType == EmojiType.STICKER))
|
||||
emojiText += $"{(emojiText.Length > 0 ? $" & {this.GetString(this.t.Commands.Utility.EmojiStealer.Sticker)}" : this.GetString(this.t.Commands.Utility.EmojiStealer.Sticker))}";
|
||||
|
||||
embed.Description = this.GetString(this.t.Commands.Utility.EmojiStealer.ReceivePrompt, true, new TVar("Type", emojiText));
|
||||
_ = embed.AsAwaitingInput(ctx);
|
||||
|
||||
var IncludeStickers = false;
|
||||
|
||||
if (!SanitizedEmoteList.Any(x => x.Value.EntryType == EmojiType.EMOJI))
|
||||
IncludeStickers = true;
|
||||
|
||||
var IncludeStickersButton = new DiscordButtonComponent((IncludeStickers ? ButtonStyle.Success : ButtonStyle.Danger), "ToggleStickers", this.GetString(this.t.Commands.Utility.EmojiStealer.ToggleStickers), !SanitizedEmoteList.Any(x => x.Value.EntryType == EmojiType.EMOJI), new DiscordComponentEmoji(DiscordEmoji.FromGuildEmote(ctx.Client, (ulong)(IncludeStickers ? 970278964755038248 : 970278964079767574))));
|
||||
|
||||
var AddToServerButton = new DiscordButtonComponent(ButtonStyle.Success, "AddToServer", this.GetString(this.t.Commands.Utility.EmojiStealer.AddEmojisToServer), !ctx.Member.Permissions.HasPermission(Permissions.ManageGuildExpressions), new DiscordComponentEmoji(DiscordEmoji.FromUnicode("➕")));
|
||||
var ZipPrivateMessageButton = new DiscordButtonComponent(ButtonStyle.Primary, "ZipPrivateMessage", this.GetString(this.t.Commands.Utility.EmojiStealer.DirectMessageZip), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("🖥")));
|
||||
var SinglePrivateMessageButton = new DiscordButtonComponent(ButtonStyle.Primary, "SinglePrivateMessage", this.GetString(this.t.Commands.Utility.EmojiStealer.DirectMessageSingle), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("📱")));
|
||||
|
||||
var SendHereButton = new DiscordButtonComponent(ButtonStyle.Secondary, "SendHere", this.GetString(this.t.Commands.Utility.EmojiStealer.CurrentChatZip), !(ctx.Member.Permissions.HasPermission(Permissions.AttachFiles)), new DiscordComponentEmoji(DiscordEmoji.FromUnicode("💬")));
|
||||
|
||||
var builder = new DiscordMessageBuilder().WithEmbed(embed);
|
||||
|
||||
if (SanitizedEmoteList.Any(x => x.Value.EntryType == EmojiType.STICKER))
|
||||
_ = builder.AddComponents(IncludeStickersButton);
|
||||
|
||||
_ = builder.AddComponents(new List<DiscordComponent> { AddToServerButton, ZipPrivateMessageButton, SinglePrivateMessageButton, SendHereButton });
|
||||
|
||||
_ = await this.RespondOrEdit(builder);
|
||||
|
||||
CancellationTokenSource cancellationTokenSource = new();
|
||||
|
||||
ctx.Client.ComponentInteractionCreated += RunInteraction;
|
||||
|
||||
_ = Task.Delay(60000, cancellationTokenSource.Token).ContinueWith(x =>
|
||||
{
|
||||
if (x.IsCompletedSuccessfully)
|
||||
{
|
||||
ctx.Client.ComponentInteractionCreated -= RunInteraction;
|
||||
FinishedInteraction = true;
|
||||
|
||||
this.ModifyToTimedOut();
|
||||
}
|
||||
});
|
||||
|
||||
async Task RunInteraction(DiscordClient s, ComponentInteractionCreateEventArgs e)
|
||||
{
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (e.Message?.Id == ctx.ResponseMessage.Id && e.User.Id == ctx.User.Id)
|
||||
{
|
||||
cancellationTokenSource.Cancel();
|
||||
cancellationTokenSource = new();
|
||||
|
||||
_ = Task.Delay(60000, cancellationTokenSource.Token).ContinueWith(x =>
|
||||
{
|
||||
if (x.IsCompletedSuccessfully)
|
||||
{
|
||||
ctx.Client.ComponentInteractionCreated -= RunInteraction;
|
||||
|
||||
this.ModifyToTimedOut();
|
||||
}
|
||||
});
|
||||
|
||||
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
|
||||
|
||||
if (e.GetCustomId() == AddToServerButton.CustomId)
|
||||
{
|
||||
ctx.Client.ComponentInteractionCreated -= RunInteraction;
|
||||
cancellationTokenSource.Cancel();
|
||||
|
||||
if (!ctx.Member.Permissions.HasPermission(Permissions.ManageGuildExpressions))
|
||||
{
|
||||
this.SendPermissionError(Permissions.ManageGuildExpressions);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ctx.CurrentMember.Permissions.HasPermission(Permissions.ManageGuildExpressions))
|
||||
{
|
||||
this.SendOwnPermissionError(Permissions.ManageGuildExpressions);
|
||||
return;
|
||||
}
|
||||
|
||||
var DiscordWarning = false;
|
||||
|
||||
embed.Description = this.GetString(this.t.Commands.Utility.EmojiStealer.AddEmojisToServerLoading, true,
|
||||
new TVar("Min", 0),
|
||||
new TVar("Max", (IncludeStickers ? SanitizedEmoteList.Count : SanitizedEmoteList.Where(x => x.Value.EntryType == EmojiType.EMOJI).Count())));
|
||||
_ = embed.AsLoading(ctx);
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(embed));
|
||||
|
||||
for (var i = 0; i < SanitizedEmoteList.Count; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
Task task;
|
||||
|
||||
switch (SanitizedEmoteList.ElementAt(i).Value.EntryType)
|
||||
{
|
||||
case EmojiType.STICKER:
|
||||
{
|
||||
var sticker = SanitizedEmoteList.ElementAt(i).Value;
|
||||
|
||||
task = ctx.Guild.CreateStickerAsync(sticker.Name, sticker.Description ?? sticker.Name, sticker.Emoji, sticker.Data.Stream, sticker.StickerFormat);
|
||||
|
||||
var WaitSeconds = 0;
|
||||
|
||||
while (task.Status == TaskStatus.WaitingForActivation)
|
||||
{
|
||||
WaitSeconds++;
|
||||
|
||||
if (WaitSeconds > 10 && !DiscordWarning)
|
||||
{
|
||||
embed.Description = this.GetString(this.t.Commands.Utility.EmojiStealer.AddStickersToServerLoading, true,
|
||||
new TVar("Min", 0),
|
||||
new TVar("Max", (IncludeStickers ? SanitizedEmoteList.Count : SanitizedEmoteList.Where(x => x.Value.EntryType == EmojiType.EMOJI).Count()))) +
|
||||
$"\n{this.GetString(this.t.Commands.Utility.EmojiStealer.AddToServerLoadingNotice)}";
|
||||
_ = await this.RespondOrEdit(embed);
|
||||
|
||||
DiscordWarning = true;
|
||||
}
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
|
||||
if (task.IsFaulted)
|
||||
throw task.Exception.InnerException;
|
||||
break;
|
||||
}
|
||||
case EmojiType.EMOJI:
|
||||
{
|
||||
var emoji = SanitizedEmoteList.ElementAt(i);
|
||||
|
||||
task = ctx.Guild.CreateEmojiAsync(SanitizedEmoteList.ElementAt(i).Value.Name, emoji.Value.Data.Stream);
|
||||
|
||||
var WaitSeconds = 0;
|
||||
|
||||
while (task.Status == TaskStatus.WaitingForActivation)
|
||||
{
|
||||
WaitSeconds++;
|
||||
|
||||
if (WaitSeconds > 10 && !DiscordWarning)
|
||||
{
|
||||
embed.Description = this.GetString(this.t.Commands.Utility.EmojiStealer.AddEmojisToServerLoading, true,
|
||||
new TVar("Min", 0),
|
||||
new TVar("Max", (IncludeStickers ? SanitizedEmoteList.Count : SanitizedEmoteList.Where(x => x.Value.EntryType == EmojiType.EMOJI).Count()))) +
|
||||
$"\n{this.GetString(this.t.Commands.Utility.EmojiStealer.AddToServerLoadingNotice)}";
|
||||
_ = await this.RespondOrEdit(embed);
|
||||
|
||||
DiscordWarning = true;
|
||||
}
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
|
||||
if (task.IsFaulted)
|
||||
throw task.Exception.InnerException;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
catch (DisCatSharp.Exceptions.BadRequestException ex)
|
||||
{
|
||||
var regex = Regex.Match(ex.WebResponse.Response.Replace("\\", ""), "((\"code\": )(\\d*))");
|
||||
|
||||
if (regex.Groups[3].Value == "30008")
|
||||
{
|
||||
embed.Description = this.GetString(this.t.Commands.Utility.EmojiStealer.NoMoreRoom, true, new TVar("Count", i));
|
||||
_ = embed.AsError(ctx);
|
||||
_ = await this.RespondOrEdit(embed);
|
||||
return;
|
||||
}
|
||||
else
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
embed.Description = this.GetString(this.t.Commands.Utility.EmojiStealer.SuccessAdded, true,
|
||||
new TVar("Count", (IncludeStickers ? SanitizedEmoteList.Count : SanitizedEmoteList.Where(x => x.Value.EntryType == EmojiType.EMOJI).Count())));
|
||||
_ = embed.AsSuccess(ctx);
|
||||
_ = await this.RespondOrEdit(embed);
|
||||
return;
|
||||
}
|
||||
else if (e.GetCustomId() == SinglePrivateMessageButton.CustomId)
|
||||
{
|
||||
ctx.Client.ComponentInteractionCreated -= RunInteraction;
|
||||
cancellationTokenSource.Cancel();
|
||||
|
||||
embed.Description = this.GetString(this.t.Commands.Utility.EmojiStealer.SendingDm, true, new TVar("Type", emojiText));
|
||||
_ = embed.AsLoading(ctx);
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(embed));
|
||||
|
||||
try
|
||||
{
|
||||
var totalCount = IncludeStickers ? SanitizedEmoteList.Count : SanitizedEmoteList.Where(x => x.Value.EntryType == EmojiType.EMOJI).Count();
|
||||
|
||||
for (var i = 0; i < SanitizedEmoteList.Count; i++)
|
||||
{
|
||||
if (!IncludeStickers)
|
||||
if (SanitizedEmoteList.ElementAt(i).Value.EntryType != EmojiType.EMOJI)
|
||||
continue;
|
||||
|
||||
var current = SanitizedEmoteList.ElementAt(i);
|
||||
_ = current.Value.Data.Stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
var currentFilename = $"{current.Value.Name}.{(current.Value.Animated == true ? "gif" : "png")}";
|
||||
|
||||
_ = await ctx.User.SendMessageAsync(new DiscordMessageBuilder()
|
||||
.WithContent($"`{i + 1}/{totalCount}` `{currentFilename}`")
|
||||
.WithFile($"{currentFilename}", current.Value.Data.Stream));
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
|
||||
_ = await ctx.User.SendMessageAsync(new DiscordMessageBuilder().WithContent(this.GetString(this.t.Commands.Utility.EmojiStealer.SuccessDm, new TVar("Type", emojiText))));
|
||||
}
|
||||
catch (DisCatSharp.Exceptions.UnauthorizedException)
|
||||
{
|
||||
this.SendDmError();
|
||||
return;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
embed.Description = this.GetString(this.t.Commands.Utility.EmojiStealer.SuccessDmMain, true,
|
||||
new TVar("Count", (IncludeStickers ? SanitizedEmoteList.Count : SanitizedEmoteList.Where(x => x.Value.EntryType == EmojiType.EMOJI).Count())),
|
||||
new TVar("Type", emojiText));
|
||||
_ = await this.RespondOrEdit(embed.AsSuccess(ctx));
|
||||
return;
|
||||
}
|
||||
else if (e.GetCustomId() == ZipPrivateMessageButton.CustomId || e.GetCustomId() == SendHereButton.CustomId)
|
||||
{
|
||||
ctx.Client.ComponentInteractionCreated -= RunInteraction;
|
||||
cancellationTokenSource.Cancel();
|
||||
|
||||
embed.Description = this.GetString(this.t.Commands.Utility.EmojiStealer.PreparingZip, true);
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(embed.AsLoading(ctx)));
|
||||
|
||||
using (var archive = new ZipArchive(zipFileStream, ZipArchiveMode.Create, true))
|
||||
{
|
||||
for (var i = 0; i < SanitizedEmoteList.Count; i++)
|
||||
{
|
||||
if (!IncludeStickers)
|
||||
if (SanitizedEmoteList.ElementAt(i).Value.EntryType != EmojiType.EMOJI)
|
||||
continue;
|
||||
|
||||
var current = SanitizedEmoteList.ElementAt(i);
|
||||
var newEntry = archive.CreateEntry(current.Value.Data.Name);
|
||||
using (var entryStream = newEntry.Open())
|
||||
await current.Value.Data.Stream.CopyToAsync(entryStream);
|
||||
}
|
||||
}
|
||||
|
||||
_ = zipFileStream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
if (e.GetCustomId() == ZipPrivateMessageButton.CustomId)
|
||||
{
|
||||
embed.Description = this.GetString(this.t.Commands.Utility.EmojiStealer.SendingZipDm, true);
|
||||
_ = await this.RespondOrEdit(embed);
|
||||
|
||||
try
|
||||
{
|
||||
_ = zipFileStream.Seek(0, SeekOrigin.Begin);
|
||||
_ = await ctx.User.SendMessageAsync(new DiscordMessageBuilder().WithFile($"Emojis.zip", zipFileStream).WithContent(this.GetString(this.t.Commands.Utility.EmojiStealer.SuccessDm, new TVar("Type", emojiText))));
|
||||
}
|
||||
catch (DisCatSharp.Exceptions.UnauthorizedException)
|
||||
{
|
||||
this.SendDmError();
|
||||
return;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
embed.Description = this.GetString(this.t.Commands.Utility.EmojiStealer.SuccessDmMain, true,
|
||||
new TVar("Count", (IncludeStickers ? SanitizedEmoteList.Count : SanitizedEmoteList.Where(x => x.Value.EntryType == EmojiType.EMOJI).Count())),
|
||||
new TVar("Type", emojiText));
|
||||
_ = await this.RespondOrEdit(embed.AsSuccess(ctx));
|
||||
}
|
||||
else if (e.GetCustomId() == SendHereButton.CustomId)
|
||||
{
|
||||
if (!ctx.Member.Permissions.HasPermission(Permissions.AttachFiles))
|
||||
{
|
||||
this.SendPermissionError(Permissions.AttachFiles);
|
||||
return;
|
||||
}
|
||||
|
||||
embed.Description = this.GetString(this.t.Commands.Utility.EmojiStealer.SendingZipChat, true);
|
||||
_ = await this.RespondOrEdit(embed);
|
||||
|
||||
embed.Description = this.GetString(this.t.Commands.Utility.EmojiStealer.SuccessChat, true,
|
||||
new TVar("Count", (IncludeStickers ? SanitizedEmoteList.Count : SanitizedEmoteList.Where(x => x.Value.EntryType == EmojiType.EMOJI).Count())),
|
||||
new TVar("Type", emojiText));
|
||||
|
||||
_ = zipFileStream.Seek(0, SeekOrigin.Begin);
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().WithFile($"Emotes.zip", zipFileStream).WithEmbed(embed.AsSuccess(ctx)));
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (e.GetCustomId() == IncludeStickersButton.CustomId)
|
||||
{
|
||||
IncludeStickers = !IncludeStickers;
|
||||
|
||||
if (!IncludeStickers)
|
||||
{
|
||||
if (!SanitizedEmoteList.Any(x => x.Value.EntryType == EmojiType.EMOJI))
|
||||
IncludeStickers = true;
|
||||
}
|
||||
|
||||
IncludeStickersButton = new DiscordButtonComponent((IncludeStickers ? ButtonStyle.Success : ButtonStyle.Danger), "ToggleStickers", this.GetString(this.t.Commands.Utility.EmojiStealer.ToggleStickers), !SanitizedEmoteList.Any(x => x.Value.EntryType == EmojiType.EMOJI), new DiscordComponentEmoji(DiscordEmoji.FromGuildEmote(ctx.Client, (ulong)(IncludeStickers ? 970278964755038248 : 970278964079767574))));
|
||||
AddToServerButton = new DiscordButtonComponent(ButtonStyle.Success, "AddToServer", (IncludeStickers ? this.GetString(this.t.Commands.Utility.EmojiStealer.AddEmojisAndStickerToServer) : this.GetString(this.t.Commands.Utility.EmojiStealer.AddEmojisToServer)), !ctx.Member.Permissions.HasPermission(Permissions.ManageGuildExpressions), new DiscordComponentEmoji(DiscordEmoji.FromUnicode("➕")));
|
||||
|
||||
var builder = new DiscordMessageBuilder().WithEmbed(embed);
|
||||
|
||||
if (SanitizedEmoteList.Any(x => x.Value.EntryType == EmojiType.STICKER))
|
||||
_ = builder.AddComponents(IncludeStickersButton);
|
||||
|
||||
_ = builder.AddComponents(new List<DiscordComponent> { AddToServerButton, ZipPrivateMessageButton, SinglePrivateMessageButton, SendHereButton });
|
||||
|
||||
_ = await this.RespondOrEdit(builder);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e.GetCustomId() != IncludeStickersButton.CustomId)
|
||||
FinishedInteraction = true;
|
||||
}
|
||||
}).Add(ctx.Bot, ctx);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
while (!FinishedInteraction)
|
||||
await Task.Delay(1000);
|
||||
|
||||
try
|
||||
{ await zipFileStream.DisposeAsync(); }
|
||||
catch { }
|
||||
foreach (var b in SanitizedEmoteList)
|
||||
try
|
||||
{ await b.Value.Data.Stream.DisposeAsync(); }
|
||||
catch { }
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
231
ProjectMakoto/Commands/Utility/GuildInfoCommand.cs
Normal file
231
ProjectMakoto/Commands/Utility/GuildInfoCommand.cs
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
// 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
|
||||
|
||||
namespace ProjectMakoto.Commands;
|
||||
|
||||
internal sealed class GuildInfoCommand : BaseCommand
|
||||
{
|
||||
public override Task ExecuteCommand(SharedCommandContext ctx, Dictionary<string, object> arguments)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
var CommandKey = this.t.Commands.Utility.GuildInfo;
|
||||
|
||||
var rawGuildId = (string?)arguments["guild"];
|
||||
|
||||
if (await ctx.DbUser.Cooldown.WaitForModerate(ctx))
|
||||
return;
|
||||
|
||||
var guildId = rawGuildId?.ToUInt64() ?? ctx.Guild.Id;
|
||||
|
||||
if (guildId == 0)
|
||||
guildId = ctx.Guild.Id;
|
||||
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(CommandKey.Fetching, true)).AsLoading(ctx));
|
||||
|
||||
_ = Directory.CreateDirectory("cache");
|
||||
|
||||
try
|
||||
{
|
||||
var guild = await ctx.Client.GetGuildAsync(guildId);
|
||||
|
||||
//var imageHash = guild.DiscoverySplashHash ?? guild.SplashHash ?? "";
|
||||
//var imageUrl = guild.DiscoverySplashUrl ?? guild.SplashUrl ?? "";
|
||||
//if (!File.Exists($"cache/{imageHash}") && !imageHash.IsNullOrWhiteSpace())
|
||||
//{
|
||||
// var fileExtension = imageUrl[..(imageUrl.LastIndexOf('?'))];
|
||||
// fileExtension = fileExtension[(fileExtension.LastIndexOf(".") + 1)..];
|
||||
|
||||
// using (var outputStream = new MemoryStream())
|
||||
// {
|
||||
// var arguments = FFMpegArguments
|
||||
// .FromPipeInput(new StreamPipeSource(await new HttpClient().GetStreamAsync(imageUrl)))
|
||||
// .OutputToPipe(new StreamPipeSink(outputStream), x => x
|
||||
// .ForceFormat("image2")
|
||||
// .WithVideoCodec(fileExtension)
|
||||
// .WithArgument(new CustomArgument("-vf scale=2048:256:force_original_aspect_ratio=decrease,pad=2048:256:-1:-1")));
|
||||
|
||||
// _ = await arguments.ProcessAsynchronously();
|
||||
|
||||
// using (var file = new FileStream($"cache/{imageHash}", FileMode.Create, FileAccess.Write))
|
||||
// {
|
||||
// outputStream.Position = 0;
|
||||
// await outputStream.CopyToAsync(file);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
var embed = new DiscordEmbedBuilder
|
||||
{
|
||||
Title = guild.Name,
|
||||
Thumbnail = new DiscordEmbedBuilder.EmbedThumbnail
|
||||
{
|
||||
Url = guild.IconUrl ?? AuditLogIcons.QuestionMark,
|
||||
},
|
||||
//ImageUrl = $"attachment://banner.png",
|
||||
Description = $"{(guild.Description.IsNullOrWhiteSpace() ? "" : $"{guild.Description}\n\n")}",
|
||||
}.AsInfo(ctx);
|
||||
|
||||
_ = embed.AddField(new DiscordEmbedField(this.GetString(CommandKey.MemberTitle), $"👥 `{guild.Members.Count}` **{this.GetString(CommandKey.MemberTitle)}**\n" +
|
||||
$"🟢 `{guild.Members.Where(x => (x.Value?.Presence?.Status ?? UserStatus.Offline) != UserStatus.Offline).Count()}` **{this.GetString(CommandKey.OnlineMembers)}**\n" +
|
||||
$"🛑 `{guild.MaxMembers}` **{this.GetString(CommandKey.MaxMembers)}**\n"));
|
||||
|
||||
_ = embed.AddField(new DiscordEmbedField(this.GetString(CommandKey.GuildTitle), $"👤 **{this.GetString(CommandKey.Owner)}**: {guild.Owner.Mention} (`{guild.Owner.GetUsernameWithIdentifier()}`)\n" +
|
||||
$"🕒 **{this.GetString(CommandKey.Creation)}**: {guild.CreationTimestamp.ToTimestamp(TimestampFormat.LongDateTime)} ({guild.CreationTimestamp.ToTimestamp()})\n" +
|
||||
$"🗺 **{this.GetString(CommandKey.Locale)}**: `{guild.PreferredLocale}`\n" +
|
||||
$"🔮 `{guild.PremiumSubscriptionCount}` **{this.GetString(CommandKey.Boosts)} (`{guild.PremiumTier switch { PremiumTier.None => this.GetString(CommandKey.BoostsNone), PremiumTier.TierOne => this.GetString(CommandKey.BoostsTierOne), PremiumTier.TierTwo => this.GetString(CommandKey.BoostsTierTwo), PremiumTier.TierThree => this.GetString(CommandKey.BoostsTierThree), PremiumTier.Unknown => "?", _ => "?", }}`)**\n\n" +
|
||||
$"😀 `{guild.Emojis.Count}` **{this.GetString(this.t.Commands.Utility.EmojiStealer.Emoji)}**\n" +
|
||||
$"🖼 `{guild.Stickers.Count}` **{this.GetString(this.t.Commands.Utility.EmojiStealer.Sticker)}**\n\n" +
|
||||
$"{(guild.WidgetEnabled ?? false).ToPillEmote(ctx.Bot)} **{this.GetString(CommandKey.Widget)}**\n" +
|
||||
$"{(guild.IsCommunity).ToPillEmote(ctx.Bot)} **{this.GetString(CommandKey.Community)}**", true));
|
||||
|
||||
_ = embed.AddField(new DiscordEmbedField(this.GetString(CommandKey.Security), $"{(guild.MfaLevel == MfaLevel.Enabled).ToPillEmote(ctx.Bot)} **{this.GetString(CommandKey.MultiFactor)}**\n" +
|
||||
$"{(guild.Features.Features.Any(x => x == GuildFeaturesEnum.HasMembershipScreeningEnabled)).ToPillEmote(ctx.Bot)} **{this.GetString(CommandKey.Screening)}**\n" +
|
||||
$"{(guild.Features.Features.Any(x => x == GuildFeaturesEnum.HasWelcomeScreenEnabled)).ToPillEmote(ctx.Bot)} **{this.GetString(CommandKey.WelcomeScreen)}**\n" +
|
||||
$"🚪 **{this.GetString(CommandKey.Verification)}**: `{guild.VerificationLevel switch { VerificationLevel.None => this.GetString(CommandKey.VerificationNone), VerificationLevel.Low => this.GetString(CommandKey.VerificationLow), VerificationLevel.Medium => this.GetString(CommandKey.VerificationMedium), VerificationLevel.High => this.GetString(CommandKey.VerificationHigh), VerificationLevel.Highest => this.GetString(CommandKey.VerificationHighest), _ => "?", }}`\n" +
|
||||
$"🔍 **{this.GetString(CommandKey.ExplicitContent)}**: `{guild.ExplicitContentFilter switch { ExplicitContentFilter.Disabled => this.GetString(CommandKey.ExplicitContentNone), ExplicitContentFilter.MembersWithoutRoles => this.GetString(CommandKey.ExplicitContentNoRoles), ExplicitContentFilter.AllMembers => this.GetString(CommandKey.ExplicitContentEveryone), _ => "?", }}`\n" +
|
||||
$"⚠ **{this.GetString(CommandKey.Nsfw)}**: `{guild.NsfwLevel switch { NsfwLevel.Default => this.GetString(CommandKey.NsfwNoRating), NsfwLevel.Explicit => this.GetString(CommandKey.NsfwExplicit), NsfwLevel.Safe => this.GetString(CommandKey.NsfwSafe), NsfwLevel.Age_Restricted => this.GetString(CommandKey.NsfwQuestionable), _ => "?", }}`\n" +
|
||||
$"💬 **{this.GetString(CommandKey.DefaultNotifications)}**: `{guild.DefaultMessageNotifications switch { DefaultMessageNotifications.AllMessages => this.GetString(CommandKey.DefaultNotificationsAll), DefaultMessageNotifications.MentionsOnly => this.GetString(CommandKey.DefaultNotificationsMentions), _ => "?", }}`\n", true));
|
||||
|
||||
_ = embed.AddField(new DiscordEmbedField(this.GetString(CommandKey.SpecialChannels), $"📑 **{this.GetString(CommandKey.Rules)}**: {guild.RulesChannel?.Mention ?? this.GetString(this.t.Common.Off, true)}\n" +
|
||||
$"📰 **{this.GetString(CommandKey.CommunityUpdates)}**: {guild.PublicUpdatesChannel?.Mention ?? this.GetString(this.t.Common.Off, true)}\n\n" +
|
||||
$"⌨ **{this.GetString(CommandKey.InactiveChannel)}**: {guild.AfkChannel?.Mention ?? this.GetString(this.t.Common.Off, true)}\n" +
|
||||
$"> **{this.GetString(CommandKey.InactiveTimeout)}**: `{((long)guild.AfkTimeout).GetHumanReadable()}`\n\n" +
|
||||
$"🤖 **{this.GetString(CommandKey.SystemMessages)}**: {guild.SystemChannel?.Mention ?? this.GetString(this.t.Common.Off, true)}\n" +
|
||||
$"> {(!guild.SystemChannelFlags.HasSystemChannelFlag(SystemChannelFlags.SuppressJoinNotifications)).ToPillEmote(ctx.Bot)} **{this.GetString(CommandKey.SystemMessagesWelcome)}**\n" +
|
||||
$"> {(!guild.SystemChannelFlags.HasSystemChannelFlag(SystemChannelFlags.SuppressJoinNotificationReplies)).ToPillEmote(ctx.Bot)} **{this.GetString(CommandKey.SystemMessagesWelcomeStickers)}**\n" +
|
||||
$"> {(!guild.SystemChannelFlags.HasSystemChannelFlag(SystemChannelFlags.SuppressPremiumSubscriptions)).ToPillEmote(ctx.Bot)} **{this.GetString(CommandKey.SystemMessagesBoost)}**\n" +
|
||||
$"> {(!guild.SystemChannelFlags.HasSystemChannelFlag(SystemChannelFlags.SuppressRoleSubbscriptionPurchaseNotification)).ToPillEmote(ctx.Bot)} **{this.GetString(CommandKey.SystemMessagesRole)}**\n" +
|
||||
$"> {(!guild.SystemChannelFlags.HasSystemChannelFlag(SystemChannelFlags.SuppressRoleSubbscriptionPurchaseNotificationReplies)).ToPillEmote(ctx.Bot)} **{this.GetString(CommandKey.SystemMessagesRoleSticker)}**\n" +
|
||||
$"> {(!guild.SystemChannelFlags.HasSystemChannelFlag(SystemChannelFlags.SuppressGuildReminderNotifications)).ToPillEmote(ctx.Bot)} **{this.GetString(CommandKey.SystemMessagesSetupTips)}**\n"));
|
||||
|
||||
if (guild.RawFeatures.Count > 0)
|
||||
_ = embed.AddField(new DiscordEmbedField(this.GetString(CommandKey.GuildFeatures), $"{string.Join(", ", guild.RawFeatures.Select(x => $"`{string.Join(" ", x.Replace("_", " ").ToLower().Split(" ").Select(x => x.FirstLetterToUpper()))}`"))}"));
|
||||
|
||||
var builder = new DiscordMessageBuilder().WithEmbed(embed);
|
||||
|
||||
if (!guild.VanityUrlCode.IsNullOrWhiteSpace())
|
||||
_ = builder.AddComponents(new DiscordLinkButtonComponent($"https://discord.gg/{guild.VanityUrlCode}", this.GetString(CommandKey.JoinServer), false, DiscordEmoji.FromUnicode("🔗").ToComponent()));
|
||||
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder()
|
||||
.WithEmbed(embed)
|
||||
.AddComponents(new DiscordLinkButtonComponent(guild.BannerUrl ?? "https://discord.gg", this.GetString(CommandKey.Banner), guild.BannerUrl is null),
|
||||
new DiscordLinkButtonComponent(guild.SplashUrl ?? "https://discord.gg", this.GetString(CommandKey.Splash), guild.BannerUrl is null),
|
||||
new DiscordLinkButtonComponent(guild.DiscoverySplashUrl ?? "https://discord.gg", this.GetString(CommandKey.DiscoverySplash), guild.BannerUrl is null),
|
||||
new DiscordLinkButtonComponent(guild.HomeHeaderUrl ?? "https://discord.gg", this.GetString(CommandKey.HomeHeader), guild.HomeHeaderUrl is null)));
|
||||
|
||||
//if (imageHash.IsNullOrWhiteSpace())
|
||||
// _ = await this.RespondOrEdit(embed);
|
||||
//else
|
||||
//{
|
||||
// using (var file = new FileStream($"cache/{imageHash}", FileMode.Open, FileAccess.Read))
|
||||
// {
|
||||
// _ = await this.RespondOrEdit(new DiscordMessageBuilder()
|
||||
// .WithEmbed(embed)
|
||||
// .WithFile("banner.png", file));
|
||||
// }
|
||||
//}
|
||||
}
|
||||
catch (Exception ex1) when (ex1 is DisCatSharp.Exceptions.UnauthorizedException or
|
||||
DisCatSharp.Exceptions.NotFoundException)
|
||||
{
|
||||
HttpClient client = new();
|
||||
|
||||
try
|
||||
{
|
||||
var preview = await ctx.Client.GetGuildPreviewAsync(guildId);
|
||||
|
||||
var embed = new DiscordEmbedBuilder
|
||||
{
|
||||
Title = preview.Name,
|
||||
Thumbnail = new DiscordEmbedBuilder.EmbedThumbnail
|
||||
{
|
||||
Url = preview.IconUrl ?? AuditLogIcons.QuestionMark,
|
||||
},
|
||||
//ImageUrl = preview.SplashUrl ?? preview.DiscoverySplashUrl ?? "",
|
||||
Description = preview.Description ?? "",
|
||||
}.AsInfo(ctx, "", this.GetString(CommandKey.GuildPreviewNotice));
|
||||
|
||||
_ = embed.AddField(new DiscordEmbedField(this.GetString(CommandKey.MemberTitle), $"👥 `{preview.ApproximateMemberCount}` **{this.GetString(CommandKey.MemberTitle)}**\n" +
|
||||
$"🟢 `{preview.ApproximatePresenceCount}` **{this.GetString(CommandKey.OnlineMembers)}**\n"));
|
||||
|
||||
_ = embed.AddField(new DiscordEmbedField(this.GetString(CommandKey.GuildTitle), $"🕒 **{this.GetString(CommandKey.Creation)}**: {preview.CreationTimestamp.ToTimestamp(TimestampFormat.LongDateTime)} ({preview.CreationTimestamp.ToTimestamp()})\n" +
|
||||
$"😀 `{preview.Emojis.Count}` **{this.GetString(this.t.Commands.Utility.EmojiStealer.Emoji)}**\n" +
|
||||
$"🖼 `{preview.Stickers.Count}` **{this.GetString(this.t.Commands.Utility.EmojiStealer.Sticker)}**\n", true));
|
||||
|
||||
_ = embed.AddField(new DiscordEmbedField(this.GetString(CommandKey.GuildFeatures), $"{string.Join(", ", preview.Features.Select(x => $"`{string.Join(" ", x.Replace("_", " ").ToLower().Split(" ").Select(x => x.FirstLetterToUpper()))}`"))}"));
|
||||
|
||||
|
||||
var builder = new DiscordMessageBuilder().WithEmbed(embed);
|
||||
|
||||
var invite = "";
|
||||
|
||||
try { invite = (await ctx.Client.GetGuildWidgetAsync(guildId)).InstantInviteUrl; } catch { }
|
||||
|
||||
if (!invite.IsNullOrWhiteSpace())
|
||||
_ = builder.AddComponents(new DiscordLinkButtonComponent(invite, this.GetString(CommandKey.JoinServer), false, DiscordEmoji.FromUnicode("🔗").ToComponent()));
|
||||
|
||||
_ = await this.RespondOrEdit(builder);
|
||||
}
|
||||
catch (Exception ex2) when (ex2 is DisCatSharp.Exceptions.UnauthorizedException or
|
||||
DisCatSharp.Exceptions.NotFoundException)
|
||||
{
|
||||
try
|
||||
{
|
||||
var widget = await ctx.Client.GetGuildWidgetAsync(guildId);
|
||||
|
||||
var embed = new DiscordEmbedBuilder
|
||||
{
|
||||
Title = widget.Name,
|
||||
}.AsInfo(ctx, "", this.GetString(CommandKey.GuildWidgetNotice));
|
||||
|
||||
_ = embed.AddField(new DiscordEmbedField(this.GetString(CommandKey.MemberTitle), $"🟢 `{widget.PresenceCount}` **{this.GetString(CommandKey.OnlineMembers)}**\n"));
|
||||
|
||||
var builder = new DiscordMessageBuilder().WithEmbed(embed);
|
||||
|
||||
if (!widget.InstantInviteUrl.IsNullOrWhiteSpace())
|
||||
_ = builder.AddComponents(new DiscordLinkButtonComponent(widget.InstantInviteUrl, this.GetString(CommandKey.JoinServer), false, DiscordEmoji.FromUnicode("🔗").ToComponent()));
|
||||
|
||||
_ = await this.RespondOrEdit(builder);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
try
|
||||
{
|
||||
var mee6 = JsonConvert.DeserializeObject<Mee6Leaderboard>(await client.GetStringAsync($"https://mee6.xyz/api/plugins/levels/leaderboard/{guildId}"));
|
||||
|
||||
var embed = new DiscordEmbedBuilder
|
||||
{
|
||||
Title = mee6.guild.name,
|
||||
Thumbnail = new DiscordEmbedBuilder.EmbedThumbnail
|
||||
{
|
||||
Url = $"https://cdn.discordapp.com/icons/{guildId}/{mee6.guild.icon}.webp?size=96",
|
||||
},
|
||||
//ImageUrl = mee6.banner_url ?? "",
|
||||
}.AsInfo(ctx, "", this.GetString(CommandKey.Mee6Notice));
|
||||
|
||||
_ = embed.AddField(new DiscordEmbedField(this.GetString(CommandKey.MemberTitle), $"👥 `{mee6.players.Length}` **{this.GetString(CommandKey.MemberTitle)}**\n"));
|
||||
|
||||
_ = await this.RespondOrEdit(embed);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
var embed = new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(CommandKey.NoGuildFound, true),
|
||||
}.AsError(ctx);
|
||||
|
||||
_ = await this.RespondOrEdit(embed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
220
ProjectMakoto/Commands/Utility/HelpCommand.cs
Normal file
220
ProjectMakoto/Commands/Utility/HelpCommand.cs
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
// 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
|
||||
|
||||
namespace ProjectMakoto.Commands;
|
||||
|
||||
internal sealed class HelpCommand : BaseCommand
|
||||
{
|
||||
public override Task ExecuteCommand(SharedCommandContext ctx, Dictionary<string, object> arguments)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
var command_filter = (string)arguments["command"];
|
||||
|
||||
if (await ctx.DbUser.Cooldown.WaitForModerate(ctx))
|
||||
return;
|
||||
|
||||
List<KeyValuePair<string, string>> Commands = new();
|
||||
var PrefixCommandsList = ctx.Client.GetCommandsNext().RegisteredCommands.GroupBy(x => x.Value.Name).Select(x => x.First()).ToList();
|
||||
|
||||
var ApplicationCommandsList = ctx.Client.GetApplicationCommands().RegisteredCommands.First(x => x.Value?.Count > 0).Value.Where(x => x.Version != 0);
|
||||
|
||||
foreach (var appCommand in ApplicationCommandsList
|
||||
.OrderByDescending(x => x.ContainingType?.GetCustomAttribute<ModulePriorityAttribute>()?.Priority ?? 0))
|
||||
{
|
||||
var nspace = appCommand?.ContainingType?.Namespace ?? "";
|
||||
var module = appCommand?.ContainingType?.Name?.Replace("Commands", "")?.ToLower() ?? "";
|
||||
|
||||
if (!nspace.Equals("ProjectMakoto.ApplicationCommands", StringComparison.InvariantCultureIgnoreCase))
|
||||
module = ctx.Bot.CommandModules.FirstOrDefault(m => m.Commands.Any(cmd => cmd.Name == appCommand.Name))?.Name ?? ctx.Bot.PluginCommandModules
|
||||
.FirstOrDefault(pl => pl.Value.Any(m => m.Commands.Any(cmd => cmd.Name == appCommand.Name)), default).Value?
|
||||
.FirstOrDefault(m => m.Commands.Any(cmd => cmd.Name == appCommand.Name))?.Name;
|
||||
|
||||
if (module.IsNullOrEmpty())
|
||||
continue;
|
||||
|
||||
switch (module)
|
||||
{
|
||||
case "configuration":
|
||||
if (!ctx.Member.IsAdmin(ctx.Bot.status))
|
||||
continue;
|
||||
break;
|
||||
case "debug":
|
||||
if (!ctx.User.IsMaintenance(ctx.Bot.status))
|
||||
continue;
|
||||
break;
|
||||
case "hidden":
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
var cmdPerm = appCommand.DefaultMemberPermissions ?? null;
|
||||
|
||||
if (cmdPerm is not null && ctx.Member.Permissions.HasPermission(cmdPerm.Value))
|
||||
continue;
|
||||
|
||||
try
|
||||
{
|
||||
var commandKey = this.t.CommandList.FirstOrDefault(localized => localized.Names.Any(x => x.Value == appCommand.Name), null);
|
||||
|
||||
string commandName;
|
||||
string commandDescription;
|
||||
string commandUsage;
|
||||
|
||||
if (commandKey is not null)
|
||||
{
|
||||
commandName = this.GetString(commandKey.Names);
|
||||
commandDescription = this.GetString(commandKey.Descriptions);
|
||||
commandUsage = string.Join(" ", commandKey.Options?.Select(x => $"<{this.GetString(x.Names).FirstLetterToUpper()}>") ?? new List<string>());
|
||||
}
|
||||
else
|
||||
{
|
||||
commandName = appCommand.Name;
|
||||
commandDescription = appCommand.Description;
|
||||
commandUsage = string.Join(" ", appCommand.Options?.Select(x => $"<{x.Name.FirstLetterToUpper()}>") ?? new List<string>());
|
||||
}
|
||||
|
||||
if (command_filter is not null)
|
||||
if (!(commandKey?.Names.Any(x => x.Value.Contains(command_filter, StringComparison.InvariantCultureIgnoreCase)) ?? false) && !commandName.Contains(command_filter, StringComparison.InvariantCultureIgnoreCase))
|
||||
continue;
|
||||
|
||||
string commandMention;
|
||||
|
||||
if (appCommand.Options?.Any(x => x.Type == ApplicationCommandOptionType.SubCommand) ?? false)
|
||||
commandMention = $"`/{commandName}`";
|
||||
else commandMention = appCommand.Type != ApplicationCommandType.ChatInput ? $"`{commandName}`" : appCommand.Mention;
|
||||
|
||||
Command? prefixCommand;
|
||||
|
||||
if (PrefixCommandsList.Any(x => x.Value.Name.Equals(appCommand.Name, StringComparison.CurrentCultureIgnoreCase)))
|
||||
prefixCommand = PrefixCommandsList.First(x => x.Value.Name.Equals(appCommand.Name, StringComparison.CurrentCultureIgnoreCase)).Value;
|
||||
else prefixCommand = appCommand.CustomAttributes.Any(x => x is PrefixCommandAlternativeAttribute)
|
||||
? PrefixCommandsList
|
||||
.First(x => x.Value.Name.ToLower() == ((PrefixCommandAlternativeAttribute)appCommand.CustomAttributes
|
||||
.First(x => x is PrefixCommandAlternativeAttribute)).PrefixCommand.ToLower().TruncateAt(' ')).Value
|
||||
: null;
|
||||
|
||||
var commandModuleName = module.ToLower() switch
|
||||
{
|
||||
"utility" => this.GetString(this.t.Commands.ModuleNames.Utility),
|
||||
"social" => this.GetString(this.t.Commands.ModuleNames.Social),
|
||||
"music" => this.GetString(this.t.Commands.ModuleNames.Music),
|
||||
"moderation" => this.GetString(this.t.Commands.ModuleNames.Moderation),
|
||||
"configuration" => this.GetString(this.t.Commands.ModuleNames.Configuration),
|
||||
_ => module.FirstLetterToUpper(),
|
||||
};
|
||||
|
||||
var TypeEmoji = appCommand.Type switch
|
||||
{
|
||||
ApplicationCommandType.ChatInput => EmojiTemplates.GetSlashCommand(ctx.Bot),
|
||||
ApplicationCommandType.Message => EmojiTemplates.GetMessageCommand(ctx.Bot),
|
||||
ApplicationCommandType.User => EmojiTemplates.GetUserCommand(ctx.Bot),
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
|
||||
Commands.Add(new KeyValuePair<string, string>($"{commandModuleName}",
|
||||
$"{TypeEmoji}{((prefixCommand is null) ? EmojiTemplates.GetPrefixCommandDisabled(ctx.Bot) : EmojiTemplates.GetPrefixCommandEnabled(ctx.Bot))} {commandMention}{(commandUsage.IsNullOrWhiteSpace() ? "" : $"`{commandUsage}`")}{(commandDescription.IsNullOrWhiteSpace() ? "" : $" - _{commandDescription}_")}"));
|
||||
|
||||
foreach (var subCmd in appCommand.Options?.Where(x => x.Type == ApplicationCommandOptionType.SubCommand) ?? new List<DiscordApplicationCommandOption>())
|
||||
{
|
||||
var subKey = commandKey?.Commands.FirstOrDefault(localized => localized.Names.Any(x => x.Value == subCmd.Name), null);
|
||||
|
||||
string subName;
|
||||
string subDescription;
|
||||
string subUsage;
|
||||
|
||||
if (subKey is not null)
|
||||
{
|
||||
subName = $"{commandName} {this.GetString(subKey.Names)}";
|
||||
subDescription = this.GetString(subKey.Descriptions);
|
||||
subUsage = string.Join(" ", subKey.Options?.Select(x => $"<{this.GetString(x.Names).FirstLetterToUpper()}>") ?? new List<string>());
|
||||
}
|
||||
else
|
||||
{
|
||||
subName = $"{commandName} {subCmd.Name}";
|
||||
subDescription = subCmd.Description;
|
||||
subUsage = string.Join(" ", subCmd.Options?.Select(x => $"<{x.Name.FirstLetterToUpper()}>") ?? new List<string>());
|
||||
}
|
||||
|
||||
Command? subPrefixCommand = null;
|
||||
|
||||
if (prefixCommand is CommandGroup group)
|
||||
subPrefixCommand = group.Children.FirstOrDefault(x => x.Name == subCmd.Name);
|
||||
|
||||
Commands.Add(new KeyValuePair<string, string>($"{commandModuleName}",
|
||||
$"{EmojiTemplates.GetInVisible(ctx.Bot)}{TypeEmoji}{(subPrefixCommand is null ? EmojiTemplates.GetPrefixCommandDisabled(ctx.Bot) : EmojiTemplates.GetPrefixCommandEnabled(ctx.Bot))} `/{subName}`{(subUsage.IsNullOrWhiteSpace() ? "" : $"`{subUsage}`")}{(subDescription.IsNullOrWhiteSpace() ? "" : $" - _{subDescription}_")}"));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex.AddData("Command", appCommand), "Failed to generate help");
|
||||
}
|
||||
}
|
||||
|
||||
if (Commands.Count == 0)
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder()
|
||||
.WithDescription(this.GetString(this.t.Commands.Utility.Help.MissingCommand, true))
|
||||
.AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
var Fields = Commands.PrepareEmbedFields();
|
||||
|
||||
var discordEmbeds = Fields.PrepareEmbeds(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.Help.Disclaimer)).AsInfo(ctx), true);
|
||||
|
||||
var Page = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
var PreviousButton = new DiscordButtonComponent(ButtonStyle.Primary, Guid.NewGuid().ToString(), this.GetString(this.t.Common.PreviousPage), (Page <= 0), DiscordEmoji.FromUnicode("◀").ToComponent());
|
||||
var NextButton = new DiscordButtonComponent(ButtonStyle.Primary, Guid.NewGuid().ToString(), this.GetString(this.t.Common.NextPage), (Page >= discordEmbeds.Count - 1), DiscordEmoji.FromUnicode("▶").ToComponent());
|
||||
|
||||
var builder = new DiscordMessageBuilder().WithEmbed(discordEmbeds.ElementAt(Page));
|
||||
|
||||
if (!PreviousButton.Disabled || !NextButton.Disabled)
|
||||
_ = builder.AddComponents(PreviousButton, NextButton);
|
||||
|
||||
_ = builder.AddComponents(MessageComponents.GetCancelButton(ctx.DbUser, ctx.Bot));
|
||||
|
||||
_ = await this.RespondOrEdit(builder);
|
||||
|
||||
if (PreviousButton.Disabled && NextButton.Disabled)
|
||||
return;
|
||||
|
||||
var Menu = await ctx.WaitForButtonAsync();
|
||||
|
||||
if (Menu.TimedOut)
|
||||
{
|
||||
this.ModifyToTimedOut();
|
||||
return;
|
||||
}
|
||||
|
||||
_ = Menu.Result.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
|
||||
|
||||
if (Menu.GetCustomId() == PreviousButton.CustomId)
|
||||
{
|
||||
Page--;
|
||||
continue;
|
||||
}
|
||||
else if (Menu.GetCustomId() == NextButton.CustomId)
|
||||
{
|
||||
Page++;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.DeleteOrInvalidate();
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
108
ProjectMakoto/Commands/Utility/LanguageCommand.cs
Normal file
108
ProjectMakoto/Commands/Utility/LanguageCommand.cs
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
// 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
|
||||
|
||||
namespace ProjectMakoto.Commands;
|
||||
|
||||
internal sealed class LanguageCommand : BaseCommand
|
||||
{
|
||||
public override Task ExecuteCommand(SharedCommandContext ctx, Dictionary<string, object> arguments)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder()
|
||||
{
|
||||
Description = $"{this.GetString(this.t.Commands.Utility.Language.Disclaimer, true)}\n" +
|
||||
$"{this.GetString(this.t.Commands.Utility.Language.Response, true)}: `{(ctx.DbUser.OverrideLocale.IsNullOrWhiteSpace() ? (ctx.DbUser.CurrentLocale.IsNullOrWhiteSpace() ? "en (Default)" : $"{ctx.DbUser.CurrentLocale} (Discord)") : $"{ctx.DbUser.OverrideLocale} (Override)")}`"
|
||||
});
|
||||
|
||||
List<DiscordStringSelectComponentOption> options = new();
|
||||
List<DiscordStringSelectComponentOption> newOptions = new();
|
||||
|
||||
newOptions.Add(new DiscordStringSelectComponentOption("Disable Override", "_", this.GetString(this.t.Commands.Utility.Language.DisableOverride), false, DiscordEmoji.FromUnicode("❌").ToComponent()));
|
||||
|
||||
options.Add(new DiscordStringSelectComponentOption("English", "en", "English"));
|
||||
options.Add(new DiscordStringSelectComponentOption("German", "de", "Deutsch"));
|
||||
options.Add(new DiscordStringSelectComponentOption("Indonesian", "id", "Bahasa Indonesia"));
|
||||
options.Add(new DiscordStringSelectComponentOption("Danish", "da", "Dansk"));
|
||||
options.Add(new DiscordStringSelectComponentOption("Spanish", "es-ES", "Español"));
|
||||
options.Add(new DiscordStringSelectComponentOption("French", "fr", "Français"));
|
||||
options.Add(new DiscordStringSelectComponentOption("Croatian", "hr", "Hrvatski"));
|
||||
options.Add(new DiscordStringSelectComponentOption("Italian", "it", "Italiano"));
|
||||
options.Add(new DiscordStringSelectComponentOption("Lithuanian", "lt", "Lietuviškai"));
|
||||
options.Add(new DiscordStringSelectComponentOption("Hungarian", "hu", "Magyar"));
|
||||
options.Add(new DiscordStringSelectComponentOption("Dutch", "nl", "Nederlands"));
|
||||
options.Add(new DiscordStringSelectComponentOption("Norwegian", "no", "Norsk"));
|
||||
options.Add(new DiscordStringSelectComponentOption("Polish", "pl", "Polski"));
|
||||
options.Add(new DiscordStringSelectComponentOption("Portuguese, Brazilian", "pt-BR", "Português do Brasil"));
|
||||
options.Add(new DiscordStringSelectComponentOption("Romanian, Romania", "ro", "Română"));
|
||||
options.Add(new DiscordStringSelectComponentOption("Finnish", "fi", "Suomi"));
|
||||
options.Add(new DiscordStringSelectComponentOption("Swedish", "sv-SE", "Svenska"));
|
||||
options.Add(new DiscordStringSelectComponentOption("Vietnamese", "vi", "Tiếng Việt"));
|
||||
options.Add(new DiscordStringSelectComponentOption("Turkish", "tr", "Türkçe"));
|
||||
options.Add(new DiscordStringSelectComponentOption("Czech", "cs", "Čeština"));
|
||||
options.Add(new DiscordStringSelectComponentOption("Greek", "el", "Ελληνικά"));
|
||||
options.Add(new DiscordStringSelectComponentOption("Bulgarian", "bg", "български"));
|
||||
options.Add(new DiscordStringSelectComponentOption("Russian", "ru", "Pусский"));
|
||||
options.Add(new DiscordStringSelectComponentOption("Ukrainian", "uk", "Українська"));
|
||||
options.Add(new DiscordStringSelectComponentOption("Hindi", "hi", "हिन्दी"));
|
||||
options.Add(new DiscordStringSelectComponentOption("Thai", "th", "ไทย"));
|
||||
options.Add(new DiscordStringSelectComponentOption("Chinese, China", "zh-CN", "中文"));
|
||||
options.Add(new DiscordStringSelectComponentOption("Japanese", "ja", "日本語"));
|
||||
options.Add(new DiscordStringSelectComponentOption("Chinese, Taiwan", "zh-TW", "繁體中文"));
|
||||
options.Add(new DiscordStringSelectComponentOption("Korean", "ko", "한국어"));
|
||||
|
||||
foreach (var b in options)
|
||||
if (this.t.Progress.TryGetValue(b.Value, out var value))
|
||||
{
|
||||
var perc = (value / (decimal)this.t.Progress["en"] * 100);
|
||||
DiscordComponentEmoji emoji = null;
|
||||
|
||||
if (perc >= 100)
|
||||
emoji = DiscordEmoji.FromUnicode("🟢").ToComponent();
|
||||
else emoji = perc >= 85 ? DiscordEmoji.FromUnicode("🟡").ToComponent() : DiscordEmoji.FromUnicode("🔴").ToComponent();
|
||||
|
||||
newOptions.Add(new DiscordStringSelectComponentOption(b.Label, b.Value, b.Description.Insert(0, $"{perc.ToString("N1", CultureInfo.CreateSpecificCulture("en-US"))}% | "), false, emoji));
|
||||
}
|
||||
|
||||
var SelectionResult = await this.PromptCustomSelection(newOptions, this.GetString(this.t.Commands.Utility.Language.Selector));
|
||||
|
||||
if (SelectionResult.TimedOut)
|
||||
{
|
||||
this.ModifyToTimedOut(true);
|
||||
return;
|
||||
}
|
||||
else if (SelectionResult.Cancelled)
|
||||
{
|
||||
this.DeleteOrInvalidate();
|
||||
return;
|
||||
}
|
||||
else if (SelectionResult.Errored)
|
||||
{
|
||||
throw SelectionResult.Exception;
|
||||
}
|
||||
|
||||
switch (SelectionResult.Result)
|
||||
{
|
||||
case "_":
|
||||
{
|
||||
ctx.DbUser.OverrideLocale = null;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
ctx.DbUser.OverrideLocale = SelectionResult.Result;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
await this.ExecuteCommand(ctx, arguments);
|
||||
return;
|
||||
});
|
||||
}
|
||||
}
|
||||
106
ProjectMakoto/Commands/Utility/LeaderboardCommand.cs
Normal file
106
ProjectMakoto/Commands/Utility/LeaderboardCommand.cs
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
// 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
|
||||
|
||||
namespace ProjectMakoto.Commands;
|
||||
internal sealed class LeaderboardCommand : BaseCommand
|
||||
{
|
||||
public override Task ExecuteCommand(SharedCommandContext ctx, Dictionary<string, object> arguments)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
var ShowAmount = (int)arguments["amount"];
|
||||
|
||||
if (await ctx.DbUser.Cooldown.WaitForModerate(ctx))
|
||||
return;
|
||||
|
||||
if (!ctx.DbGuild.Experience.UseExperience)
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(this.t.Commands.Utility.Leaderboard.Disabled, true,
|
||||
new TVar("Command", $"{ctx.Prefix}experiencesettings config"))
|
||||
}.AsError(ctx, this.GetString(this.t.Commands.Utility.Leaderboard.Title)));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ShowAmount is > 50 or < 3)
|
||||
{
|
||||
this.SendSyntaxError();
|
||||
return;
|
||||
}
|
||||
|
||||
var embed = new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(this.t.Commands.Utility.Leaderboard.Fetching, true),
|
||||
}.AsLoading(ctx, this.GetString(this.t.Commands.Utility.Leaderboard.Title));
|
||||
|
||||
_ = await this.RespondOrEdit(embed: embed);
|
||||
|
||||
var count = 0;
|
||||
|
||||
var currentuserplacement = 0;
|
||||
|
||||
foreach (var b in ctx.DbGuild.Members.Fetch().OrderByDescending(x => x.Value.Experience.Points))
|
||||
{
|
||||
currentuserplacement++;
|
||||
if (b.Key == ctx.User.Id)
|
||||
break;
|
||||
}
|
||||
|
||||
var members = await ctx.Guild.GetAllMembersAsync();
|
||||
|
||||
List<KeyValuePair<string, string>> Board = new();
|
||||
|
||||
foreach (var b in ctx.DbGuild.Members.Fetch().OrderByDescending(x => x.Value.Experience.Points))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!members.Any(x => x.Id == b.Key))
|
||||
continue;
|
||||
|
||||
var bMember = members.First(x => x.Id == b.Key);
|
||||
|
||||
if (bMember is null)
|
||||
continue;
|
||||
|
||||
if (bMember.IsBot)
|
||||
continue;
|
||||
|
||||
if (b.Value.Experience.Points <= 1)
|
||||
break;
|
||||
|
||||
count++;
|
||||
|
||||
Board.Add(new KeyValuePair<string, string>(" ", $"**{count.ToEmotes()}**. <@{b.Key}> `{bMember.GetUsernameWithIdentifier()}` ({this.GetString(this.t.Commands.Utility.Leaderboard.Level, true, new TVar("Level", b.Value.Experience.Level), new TVar("Points", b.Value.Experience.Points))}"));
|
||||
|
||||
if (count >= ShowAmount)
|
||||
break;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
var fields = Board.PrepareEmbedFields();
|
||||
|
||||
foreach (var field in fields)
|
||||
_ = embed.AddField(new DiscordEmbedField(field.Key, field.Value));
|
||||
|
||||
if (count != 0)
|
||||
{
|
||||
embed.Author.IconUrl = ctx.Guild.IconUrl;
|
||||
embed.Description = this.GetString(this.t.Commands.Utility.Leaderboard.Placement, new TVar("Placement", currentuserplacement));
|
||||
_ = await this.RespondOrEdit(embed.AsInfo(ctx, this.GetString(this.t.Commands.Utility.Leaderboard.Title)));
|
||||
}
|
||||
else
|
||||
{
|
||||
embed.Description = $":no_entry_sign: {this.GetString(this.t.Commands.Utility.Leaderboard.NoPoints, true)}";
|
||||
_ = await this.RespondOrEdit(embed.AsInfo(ctx, this.GetString(this.t.Commands.Utility.Leaderboard.Title)));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
49
ProjectMakoto/Commands/Utility/RankCommand.cs
Normal file
49
ProjectMakoto/Commands/Utility/RankCommand.cs
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
// 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
|
||||
|
||||
namespace ProjectMakoto.Commands;
|
||||
internal sealed class RankCommand : BaseCommand
|
||||
{
|
||||
public override Task ExecuteCommand(SharedCommandContext ctx, Dictionary<string, object> arguments)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
var victim = (DiscordUser)arguments["user"];
|
||||
|
||||
if (await ctx.DbUser.Cooldown.WaitForLight(ctx))
|
||||
return;
|
||||
|
||||
if (!ctx.DbGuild.Experience.UseExperience)
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(this.t.Commands.Utility.Leaderboard.Disabled, true,
|
||||
new TVar("Command", $"{ctx.Prefix}experiencesettings config"))
|
||||
}.AsError(ctx, this.GetString(this.t.Commands.Utility.Rank.Title)));
|
||||
return;
|
||||
}
|
||||
|
||||
victim ??= ctx.User;
|
||||
|
||||
victim = await victim.GetFromApiAsync();
|
||||
|
||||
var current = (long)Math.Floor((decimal)(ctx.DbGuild.Members[victim.Id].Experience.Points - ctx.Bot.ExperienceHandler.CalculateLevelRequirement(ctx.DbGuild.Members[victim.Id].Experience.Level - 1)));
|
||||
var max = (long)Math.Floor((decimal)(ctx.Bot.ExperienceHandler.CalculateLevelRequirement(ctx.DbGuild.Members[victim.Id].Experience.Level) - ctx.Bot.ExperienceHandler.CalculateLevelRequirement(ctx.DbGuild.Members[victim.Id].Experience.Level - 1)));
|
||||
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = $"{(victim.Id == ctx.User.Id ? this.GetString(this.t.Commands.Utility.Rank.Self, new TVar("Level", ctx.DbGuild.Members[victim.Id].Experience.Level.ToEmotes()), new TVar("Points", ctx.DbGuild.Members[victim.Id].Experience.Points.ToString("N0", CultureInfo.GetCultureInfo("en-US")))) : this.GetString(this.t.Commands.Utility.Rank.Other, new TVar("User", victim.Mention), new TVar("Level", ctx.DbGuild.Members[victim.Id].Experience.Level.ToEmotes()), new TVar("Points", ctx.DbGuild.Members[victim.Id].Experience.Points.ToString("N0", CultureInfo.GetCultureInfo("en-US")))))}\n\n" +
|
||||
$"**{this.GetString(this.t.Commands.Utility.Rank.Progress, new TVar("Level", (ctx.DbGuild.Members[victim.Id].Experience.Level + 1).ToEmotes()))}**\n" +
|
||||
$"`{Math.Floor((decimal)((decimal)((decimal)current / (decimal)max) * 100)).ToString().Replace(",", ".")}%` " +
|
||||
$"`{StringTools.GenerateASCIIProgressbar(current, max, 44)}` " +
|
||||
$"`{current}/{max} XP`",
|
||||
}.AsInfo(ctx, this.GetString(this.t.Commands.Utility.Rank.Title)));
|
||||
});
|
||||
}
|
||||
}
|
||||
217
ProjectMakoto/Commands/Utility/RemindersCommand.cs
Normal file
217
ProjectMakoto/Commands/Utility/RemindersCommand.cs
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
// 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 ProjectMakoto.Entities.Users;
|
||||
|
||||
namespace ProjectMakoto.Commands;
|
||||
|
||||
internal sealed class RemindersCommand : BaseCommand
|
||||
{
|
||||
public override Task ExecuteCommand(SharedCommandContext ctx, Dictionary<string, object> arguments)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
string? snoozeDescription = null;
|
||||
|
||||
if ((arguments?.Count ?? 0) > 0)
|
||||
snoozeDescription = arguments["description"]?.ToString();
|
||||
|
||||
if (await ctx.DbUser.Cooldown.WaitForModerate(ctx))
|
||||
return;
|
||||
|
||||
var rem = ctx.DbUser.Reminders;
|
||||
|
||||
var AddButton = new DiscordButtonComponent(ButtonStyle.Primary, Guid.NewGuid().ToString(), this.GetString(this.t.Commands.Utility.Reminders.NewReminder), (rem.ScheduledReminders.Length >= 10), DiscordEmoji.FromUnicode("➕").ToComponent());
|
||||
var RemoveButton = new DiscordButtonComponent(ButtonStyle.Primary, Guid.NewGuid().ToString(), this.GetString(this.t.Commands.Utility.Reminders.DeleteReminder), (rem.ScheduledReminders.Length <= 0), DiscordEmoji.FromUnicode("➖").ToComponent());
|
||||
var SelectedCustomId = (snoozeDescription is null ? "" : AddButton.CustomId);
|
||||
|
||||
if (snoozeDescription is null)
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder()
|
||||
.WithEmbed(new DiscordEmbedBuilder()
|
||||
.WithDescription($"{this.GetString(this.t.Commands.Utility.Reminders.Count, true, new TVar("Count", rem.ScheduledReminders.Length))}\n\n" +
|
||||
$"{string.Join("\n\n", rem.ScheduledReminders.Select(x => $"> {x.Description.FullSanitize()}\n{this.GetString(this.t.Commands.Utility.Reminders.CreatedOn, new TVar("Guild", $"**{x.CreationPlace}**"))}\n{this.GetString(this.t.Commands.Utility.Reminders.DueTime, new TVar("Relative", x.DueTime.ToTimestamp()), new TVar("DateTime", x.DueTime.ToTimestamp(TimestampFormat.LongDateTime)))}").ToList())}\n\n" +
|
||||
$"**⚠ {this.GetString(this.t.Commands.Utility.Reminders.Notice)}**")
|
||||
.AsInfo(ctx, this.GetString(this.t.Commands.Utility.Reminders.Title)))
|
||||
.AddComponents(new List<DiscordComponent> { AddButton, RemoveButton })
|
||||
.AddComponents(MessageComponents.GetCancelButton(ctx.DbUser, ctx.Bot)));
|
||||
|
||||
var Button = await ctx.WaitForButtonAsync(TimeSpan.FromMinutes(2));
|
||||
|
||||
if (Button.TimedOut)
|
||||
{
|
||||
this.ModifyToTimedOut(true);
|
||||
return;
|
||||
}
|
||||
|
||||
_ = Button.Result.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
|
||||
SelectedCustomId = Button.GetCustomId();
|
||||
}
|
||||
|
||||
if (SelectedCustomId == AddButton.CustomId)
|
||||
{
|
||||
var selectedDescription = snoozeDescription.IsNullOrWhiteSpace() ? "" : snoozeDescription;
|
||||
DateTime? selectedDueDate = null;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (selectedDueDate.HasValue && (selectedDueDate.Value.Ticks < DateTime.UtcNow.Ticks || selectedDueDate.Value.GetTimespanUntil() > TimeSpan.FromDays(30 * 6)))
|
||||
{
|
||||
selectedDueDate = null;
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.Reminders.InvalidDateTime, true)).AsError(ctx));
|
||||
await Task.Delay(5000);
|
||||
}
|
||||
|
||||
var SelectDescriptionButton = new DiscordButtonComponent((selectedDescription.IsNullOrWhiteSpace() ? ButtonStyle.Primary : ButtonStyle.Secondary), Guid.NewGuid().ToString(), this.GetString(this.t.Commands.Utility.Reminders.SetDescription), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("✏")));
|
||||
var SelectDueDateButton = new DiscordButtonComponent((selectedDueDate is null ? ButtonStyle.Primary : ButtonStyle.Secondary), Guid.NewGuid().ToString(), this.GetString(this.t.Commands.Utility.Reminders.SetDateTime), (selectedDescription is null), new DiscordComponentEmoji(DiscordEmoji.FromUnicode("🕒")));
|
||||
var Finish = new DiscordButtonComponent(ButtonStyle.Success, Guid.NewGuid().ToString(), this.GetString(this.t.Common.Submit), (selectedDescription.IsNullOrWhiteSpace() || selectedDueDate is null), new DiscordComponentEmoji(DiscordEmoji.FromUnicode("✅")));
|
||||
|
||||
var padding = TranslationUtil.CalculatePadding(ctx.DbUser, this.t.Commands.Utility.Reminders.Description, this.t.Commands.Utility.Reminders.DateTime);
|
||||
|
||||
var action_embed = new DiscordEmbedBuilder
|
||||
{
|
||||
Description = $"`{this.GetString(this.t.Commands.Utility.Reminders.Description).PadRight(padding)}`: {(selectedDescription.IsNullOrWhiteSpace() ? $"`{this.GetString(this.t.Common.NotSelected)}`" : $"`{selectedDescription.FullSanitize()}`")}\n" +
|
||||
$"`{this.GetString(this.t.Commands.Utility.Reminders.DateTime).PadRight(padding)}`: {(selectedDueDate is null ? $"`{this.GetString(this.t.Common.NotSelected)}`" : $"{selectedDueDate.Value.ToTimestamp(TimestampFormat.LongDateTime)} ({selectedDueDate.Value.ToTimestamp()})")}"
|
||||
}.AsAwaitingInput(ctx, this.GetString(this.t.Commands.Utility.Reminders.Title));
|
||||
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(action_embed)
|
||||
.AddComponents(new List<DiscordComponent> { SelectDescriptionButton, SelectDueDateButton, Finish })
|
||||
.AddComponents(MessageComponents.GetBackButton(ctx.DbUser, ctx.Bot)));
|
||||
|
||||
var Menu = await ctx.WaitForButtonAsync();
|
||||
|
||||
if (Menu.TimedOut)
|
||||
{
|
||||
this.ModifyToTimedOut();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Menu.GetCustomId() == SelectDescriptionButton.CustomId)
|
||||
{
|
||||
var maxLength = 100 - JsonConvert.SerializeObject(new ReminderSnoozeButton(), new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Include }).Length;
|
||||
|
||||
var modal = new DiscordInteractionModalBuilder(this.GetString(this.t.Commands.Utility.Reminders.NewReminder), Guid.NewGuid().ToString())
|
||||
.AddTextComponent(new DiscordTextComponent(TextComponentStyle.Small, "desc", this.GetString(this.t.Commands.Utility.Reminders.Description), this.GetString(this.t.Commands.Utility.Reminders.SetDescription), 1, maxLength, true));
|
||||
|
||||
|
||||
var ModalResult = await this.PromptModalWithRetry(Menu.Result.Interaction, modal, false);
|
||||
|
||||
if (ModalResult.TimedOut)
|
||||
{
|
||||
this.ModifyToTimedOut(true);
|
||||
return;
|
||||
}
|
||||
else if (ModalResult.Cancelled)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (ModalResult.Errored)
|
||||
{
|
||||
throw ModalResult.Exception;
|
||||
}
|
||||
|
||||
selectedDescription = ModalResult.Result.Interaction.GetModalValueByCustomId("desc").TruncateWithIndication(maxLength);
|
||||
}
|
||||
else if (Menu.GetCustomId() == SelectDueDateButton.CustomId)
|
||||
{
|
||||
_ = Menu.Result.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
|
||||
|
||||
var ModalResult = await this.PromptModalForDateTime(selectedDueDate ?? DateTime.UtcNow.AddMinutes(5), false);
|
||||
|
||||
if (ModalResult.TimedOut)
|
||||
{
|
||||
this.ModifyToTimedOut(true);
|
||||
return;
|
||||
}
|
||||
else if (ModalResult.Cancelled)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (ModalResult.Errored)
|
||||
{
|
||||
if (ModalResult.Exception.GetType() == typeof(ArgumentException) || ModalResult.Exception.GetType() == typeof(ArgumentOutOfRangeException))
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.Reminders.InvalidDateTime, true)).AsError(ctx));
|
||||
await Task.Delay(5000);
|
||||
continue;
|
||||
}
|
||||
|
||||
throw ModalResult.Exception;
|
||||
}
|
||||
|
||||
selectedDueDate = ModalResult.Result;
|
||||
}
|
||||
else if (Menu.GetCustomId() == Finish.CustomId)
|
||||
{
|
||||
_ = Menu.Result.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
|
||||
|
||||
if (selectedDueDate < DateTime.UtcNow)
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.Reminders.InvalidDateTime, true)).AsError(ctx, this.GetString(this.t.Commands.Utility.Reminders.Title)));
|
||||
await Task.Delay(2000);
|
||||
continue;
|
||||
}
|
||||
|
||||
rem.ScheduledReminders = rem.ScheduledReminders.Add(new()
|
||||
{
|
||||
Description = selectedDescription,
|
||||
DueTime = selectedDueDate.Value.ToUniversalTime(),
|
||||
CreationPlace = ctx.Channel.IsPrivate ? $"[`@{ctx.CurrentUser.GetUsername()}`](https://discord.com/channels/@me/{ctx.Channel.Id})" : $"[`{ctx.Guild.Name}`](https://discord.com/channels/{ctx.Guild.Id}/{ctx.Channel.Id})"
|
||||
});
|
||||
|
||||
await this.ExecuteCommand(ctx, null);
|
||||
return;
|
||||
}
|
||||
else if (Menu.GetCustomId() == MessageComponents.BackButtonId)
|
||||
{
|
||||
_ = Menu.Result.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
|
||||
|
||||
await this.ExecuteCommand(ctx, null);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (SelectedCustomId == RemoveButton.CustomId)
|
||||
{
|
||||
if (rem.ScheduledReminders.Length == 0)
|
||||
{
|
||||
await this.ExecuteCommand(ctx, null);
|
||||
return;
|
||||
}
|
||||
|
||||
var UuidResult = await this.PromptCustomSelection(rem.ScheduledReminders
|
||||
.Select(x => new DiscordStringSelectComponentOption($"{x.Description}".TruncateWithIndication(100), x.UUID, $"in {x.DueTime.GetTotalSecondsUntil().GetHumanReadable()}")).ToList());
|
||||
|
||||
if (UuidResult.TimedOut)
|
||||
{
|
||||
this.ModifyToTimedOut();
|
||||
return;
|
||||
}
|
||||
else if (UuidResult.Cancelled)
|
||||
{
|
||||
await this.ExecuteCommand(ctx, null);
|
||||
return;
|
||||
}
|
||||
else if (UuidResult.Errored)
|
||||
{
|
||||
throw UuidResult.Exception;
|
||||
}
|
||||
|
||||
rem.ScheduledReminders = rem.ScheduledReminders.Remove(x => x.UUID, rem.ScheduledReminders.First(x => x.UUID == UuidResult.Result));
|
||||
await this.ExecuteCommand(ctx, null);
|
||||
return;
|
||||
}
|
||||
else if (SelectedCustomId == MessageComponents.CancelButtonId)
|
||||
{
|
||||
this.DeleteOrInvalidate();
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
197
ProjectMakoto/Commands/Utility/ReportHostCommand.cs
Normal file
197
ProjectMakoto/Commands/Utility/ReportHostCommand.cs
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
// 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
|
||||
|
||||
namespace ProjectMakoto.Commands;
|
||||
|
||||
internal sealed class ReportHostCommand : BaseCommand
|
||||
{
|
||||
public override Task ExecuteCommand(SharedCommandContext ctx, Dictionary<string, object> arguments)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
var url = (string)arguments["url"];
|
||||
|
||||
if (await ctx.DbUser.Cooldown.WaitForHeavy(ctx))
|
||||
return;
|
||||
|
||||
var tos_version = 3;
|
||||
|
||||
if (ctx.DbUser.UrlSubmissions.AcceptedTOS != tos_version)
|
||||
{
|
||||
var button = new DiscordButtonComponent(ButtonStyle.Primary, "accepted-tos", this.GetString(this.t.Commands.Utility.ReportHost.AcceptTos), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("👍")));
|
||||
|
||||
var tos_embed = new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(this.t.Commands.Utility.ReportHost.Tos,
|
||||
new TVar("1", 1.ToEmotes()),
|
||||
new TVar("2", 2.ToEmotes()),
|
||||
new TVar("3", 3.ToEmotes()),
|
||||
new TVar("4", 4.ToEmotes()))
|
||||
}.AsAwaitingInput(ctx, this.GetString(this.t.Commands.Utility.ReportHost.Title));
|
||||
|
||||
if (ctx.DbUser.UrlSubmissions.AcceptedTOS != 0 && ctx.DbUser.UrlSubmissions.AcceptedTOS < tos_version)
|
||||
{
|
||||
tos_embed.Description = tos_embed.Description.Insert(0, $"**{this.GetString(this.t.Commands.Utility.ReportHost.TosChangedNotice)}**\n\n");
|
||||
}
|
||||
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(tos_embed).AddComponents(button));
|
||||
|
||||
var TosAccept = await ctx.WaitForButtonAsync(TimeSpan.FromMinutes(2));
|
||||
|
||||
if (TosAccept.TimedOut)
|
||||
{
|
||||
this.ModifyToTimedOut(true);
|
||||
return;
|
||||
}
|
||||
|
||||
await TosAccept.Result.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
|
||||
|
||||
ctx.DbUser.UrlSubmissions.AcceptedTOS = tos_version;
|
||||
}
|
||||
|
||||
var embed = new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(this.t.Commands.Utility.ReportHost.Processing, true)
|
||||
}.AsLoading(ctx, this.GetString(this.t.Commands.Utility.ReportHost.Title));
|
||||
|
||||
_ = await this.RespondOrEdit(embed);
|
||||
|
||||
if (ctx.DbUser.UrlSubmissions.LastTime.AddMinutes(45) > DateTime.UtcNow && !ctx.User.IsMaintenance(ctx.Bot.status))
|
||||
{
|
||||
embed.Description = this.GetString(this.t.Commands.Utility.ReportHost.CooldownError, true,
|
||||
new TVar("Timestamp", ctx.DbUser.UrlSubmissions.LastTime.AddMinutes(45).ToTimestamp()));
|
||||
_ = this.RespondOrEdit(embed.AsError(ctx, this.GetString(this.t.Commands.Utility.ReportHost.Title)));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.Bot.SubmittedHosts.Fetch().Any(x => x.Value.Submitter == ctx.User.Id) && !ctx.User.IsMaintenance(ctx.Bot.status))
|
||||
{
|
||||
if (ctx.Bot.SubmittedHosts.Fetch().Where(x => x.Value.Submitter == ctx.User.Id).Count() >= 5)
|
||||
{
|
||||
embed.Description = this.GetString(this.t.Commands.Utility.ReportHost.LimitError, true);
|
||||
_ = this.RespondOrEdit(embed.AsError(ctx, this.GetString(this.t.Commands.Utility.ReportHost.Title)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
string host;
|
||||
|
||||
try
|
||||
{
|
||||
host = new UriBuilder(url).Host;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
embed.Description = this.GetString(this.t.Commands.Utility.ReportHost.InvalidHost, true,
|
||||
new TVar("Host", url, true));
|
||||
_ = this.RespondOrEdit(embed.AsError(ctx, this.GetString(this.t.Commands.Utility.ReportHost.Title)));
|
||||
return;
|
||||
}
|
||||
|
||||
embed.Description = this.GetString(this.t.Commands.Utility.ReportHost.ConfirmHost, true,
|
||||
new TVar("Host", host, true));
|
||||
_ = embed.AsAwaitingInput(ctx, this.GetString(this.t.Commands.Utility.ReportHost.Title));
|
||||
|
||||
var ContinueButton = new DiscordButtonComponent(ButtonStyle.Success, Guid.NewGuid().ToString(), this.GetString(this.t.Common.Confirm), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("✅")));
|
||||
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(embed).AddComponents(new List<DiscordComponent>
|
||||
{
|
||||
{ ContinueButton },
|
||||
{ MessageComponents.GetCancelButton(ctx.DbUser, ctx.Bot) }
|
||||
}));
|
||||
|
||||
var e = await ctx.WaitForButtonAsync(TimeSpan.FromMinutes(2));
|
||||
|
||||
if (e.TimedOut)
|
||||
{
|
||||
this.ModifyToTimedOut(true);
|
||||
return;
|
||||
}
|
||||
|
||||
await e.Result.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
|
||||
|
||||
if (e.GetCustomId() == ContinueButton.CustomId)
|
||||
{
|
||||
_ = embed.AsLoading(ctx, this.GetString(this.t.Commands.Utility.ReportHost.Title));
|
||||
|
||||
embed.Description = this.GetString(this.t.Commands.Utility.ReportHost.DatabaseCheck, true);
|
||||
_ = await this.RespondOrEdit(embed);
|
||||
|
||||
foreach (var b in ctx.Bot.PhishingHosts)
|
||||
{
|
||||
if (host.Contains(b.Key))
|
||||
{
|
||||
embed.Description = this.GetString(this.t.Commands.Utility.ReportHost.DatabaseError, true, new TVar("Host", host, true));
|
||||
_ = embed.AsError(ctx, this.GetString(this.t.Commands.Utility.ReportHost.Title));
|
||||
_ = this.RespondOrEdit(embed.Build());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
embed.Description = this.GetString(this.t.Commands.Utility.ReportHost.SubmissionCheck, true);
|
||||
_ = await this.RespondOrEdit(embed);
|
||||
|
||||
foreach (var b in ctx.Bot.SubmittedHosts)
|
||||
{
|
||||
if (b.Value.Url == host)
|
||||
{
|
||||
embed.Description = this.GetString(this.t.Commands.Utility.ReportHost.SubmissionError, true, new TVar("Host", host, true));
|
||||
_ = embed.AsError(ctx, this.GetString(this.t.Commands.Utility.ReportHost.Title));
|
||||
_ = this.RespondOrEdit(embed.Build());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
embed.Description = this.GetString(this.t.Commands.Utility.ReportHost.CreatingSubmission, true);
|
||||
_ = await this.RespondOrEdit(embed);
|
||||
|
||||
var channel = await ctx.Client.GetChannelAsync(ctx.Bot.status.LoadedConfig.Channels.UrlSubmissions);
|
||||
|
||||
var AcceptSubmission = new DiscordButtonComponent(ButtonStyle.Success, "accept_submission", "Accept submission", false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("✅")));
|
||||
var DenySubmission = new DiscordButtonComponent(ButtonStyle.Danger, "deny_submission", "Deny submission", false, new DiscordComponentEmoji(DiscordEmoji.FromGuildEmote(ctx.Client, 1005430134070841395)));
|
||||
var BanUserButton = new DiscordButtonComponent(ButtonStyle.Danger, "ban_user", "Deny submission & ban submitter", false, new DiscordComponentEmoji(DiscordEmoji.FromGuildEmote(ctx.Client, 1005430134070841395)));
|
||||
var BanGuildButton = new DiscordButtonComponent(ButtonStyle.Danger, "ban_guild", "Deny submission & ban guild", false, new DiscordComponentEmoji(DiscordEmoji.FromGuildEmote(ctx.Client, 1005430134070841395)));
|
||||
|
||||
var submittedMsg = await channel.SendMessageAsync(new DiscordMessageBuilder().WithEmbed(new DiscordEmbedBuilder
|
||||
{
|
||||
Author = new DiscordEmbedBuilder.EmbedAuthor { IconUrl = StatusIndicatorIcons.Success, Name = this.GetString(this.t.Commands.Utility.ReportHost.Title) },
|
||||
Color = EmbedColors.Success,
|
||||
Timestamp = DateTime.UtcNow,
|
||||
Description = $"`Submitted host`: `{host.SanitizeForCode()}`\n" +
|
||||
$"`Submission by `: `{ctx.User.GetUsernameWithIdentifier()} ({ctx.User.Id})`\n" +
|
||||
$"`Submitted on `: `{ctx.Guild.Name} ({ctx.Guild.Id})`"
|
||||
})
|
||||
.AddComponents(new List<DiscordComponent>
|
||||
{
|
||||
{ AcceptSubmission },
|
||||
{ DenySubmission },
|
||||
{ BanUserButton },
|
||||
{ BanGuildButton },
|
||||
}));
|
||||
|
||||
ctx.Bot.SubmittedHosts.Add(submittedMsg.Id, new SubmittedUrlEntry(ctx.Bot, submittedMsg.Id)
|
||||
{
|
||||
Url = host,
|
||||
Submitter = ctx.User.Id,
|
||||
GuildOrigin = ctx.Guild.Id
|
||||
});
|
||||
|
||||
ctx.DbUser.UrlSubmissions.LastTime = DateTime.UtcNow;
|
||||
|
||||
embed.Description = this.GetString(this.t.Commands.Utility.ReportHost.SubmissionCreated, true);
|
||||
_ = embed.AsSuccess(ctx, this.GetString(this.t.Commands.Utility.ReportHost.Title));
|
||||
_ = await this.RespondOrEdit(embed);
|
||||
}
|
||||
else if (e.GetCustomId() == MessageComponents.CancelButtonId)
|
||||
{
|
||||
this.DeleteOrInvalidate();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
155
ProjectMakoto/Commands/Utility/ReportTranslationCommand.cs
Normal file
155
ProjectMakoto/Commands/Utility/ReportTranslationCommand.cs
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
// 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 Octokit;
|
||||
|
||||
namespace ProjectMakoto.Commands;
|
||||
|
||||
internal sealed class ReportTranslationCommand : BaseCommand
|
||||
{
|
||||
internal static readonly string[] labels = new string[] { "Translations", "Low Priority" };
|
||||
|
||||
public override Task ExecuteCommand(SharedCommandContext ctx, Dictionary<string, object> arguments)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
var CommandKey = this.t.Commands.Utility.ReportTranslation;
|
||||
|
||||
if (await ctx.DbUser.Cooldown.WaitForHeavy(ctx))
|
||||
return;
|
||||
|
||||
var affectedType = (ReportTranslationType)arguments["affected_type"];
|
||||
var reasonType = (ReportTranslationReason)arguments["report_type"];
|
||||
var component = (string)arguments["component"];
|
||||
var additionalInformation = (string?)arguments["additional_information"];
|
||||
|
||||
var tos_version = 1;
|
||||
|
||||
if (ctx.DbUser.TranslationReports.AcceptedTOS != tos_version)
|
||||
{
|
||||
var button = new DiscordButtonComponent(ButtonStyle.Primary, "accepted-tos", this.GetString(CommandKey.AcceptTos), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("👍")));
|
||||
|
||||
var tos_embed = new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(CommandKey.Tos,
|
||||
new TVar("1", 1.ToEmotes()),
|
||||
new TVar("2", 2.ToEmotes()),
|
||||
new TVar("3", 3.ToEmotes()),
|
||||
new TVar("4", 4.ToEmotes()))
|
||||
}.AsAwaitingInput(ctx, this.GetString(CommandKey.Title));
|
||||
|
||||
if (ctx.DbUser.TranslationReports.AcceptedTOS != 0 && ctx.DbUser.TranslationReports.AcceptedTOS < tos_version)
|
||||
{
|
||||
tos_embed.Description = tos_embed.Description.Insert(0, $"**{this.GetString(CommandKey.TosChangedNotice)}**\n\n");
|
||||
}
|
||||
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(tos_embed).AddComponents(button));
|
||||
|
||||
var TosAccept = await ctx.WaitForButtonAsync(TimeSpan.FromMinutes(2));
|
||||
|
||||
if (TosAccept.TimedOut)
|
||||
{
|
||||
this.ModifyToTimedOut(true);
|
||||
return;
|
||||
}
|
||||
|
||||
await TosAccept.Result.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
|
||||
|
||||
ctx.DbUser.TranslationReports.AcceptedTOS = tos_version;
|
||||
}
|
||||
|
||||
if (ctx.Bot.status.LoadedConfig.Secrets.Github.TokenExperiation.GetTotalSecondsUntil() <= 0)
|
||||
throw new Exception("Required login data for report outdated.");
|
||||
|
||||
if (ctx.DbUser.TranslationReports.FirstRequestTime.GetTimespanSince() > TimeSpan.FromHours(24))
|
||||
{
|
||||
ctx.DbUser.TranslationReports.RequestCount = 0;
|
||||
ctx.DbUser.TranslationReports.FirstRequestTime = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
if (ctx.DbUser.TranslationReports.RequestCount >= 3)
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder()
|
||||
.WithDescription(this.GetString(CommandKey.RatelimitReached, true, new TVar("Timestamp", ctx.DbUser.TranslationReports.FirstRequestTime.AddHours(24).ToTimestamp())))
|
||||
.AsError(ctx, this.GetString(CommandKey.Title)));
|
||||
return;
|
||||
}
|
||||
|
||||
var YesButton = new DiscordButtonComponent(ButtonStyle.Success, Guid.NewGuid().ToString(), this.GetString(this.t.Common.Yes), false, "✅".UnicodeToEmoji().ToComponent());
|
||||
var NoButton = new DiscordButtonComponent(ButtonStyle.Danger, Guid.NewGuid().ToString(), this.GetString(this.t.Common.No), false, "❌".UnicodeToEmoji().ToComponent());
|
||||
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder()
|
||||
.AddEmbed(new DiscordEmbedBuilder()
|
||||
.WithDescription($"{this.GetString(CommandKey.ConfirmationPrompt, true)}")
|
||||
.AsAwaitingInput(ctx, this.GetString(CommandKey.Title)))
|
||||
.AddComponents(YesButton, NoButton));
|
||||
|
||||
var result = await ctx.ResponseMessage.WaitForButtonAsync(ctx.User);
|
||||
|
||||
if (result.TimedOut)
|
||||
{
|
||||
this.ModifyToTimedOut();
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.Result.GetCustomId() != YesButton.CustomId)
|
||||
{
|
||||
this.DeleteOrInvalidate();
|
||||
return;
|
||||
}
|
||||
|
||||
string GetReason(ReportTranslationReason reason)
|
||||
{
|
||||
return reason switch
|
||||
{
|
||||
ReportTranslationReason.MissingTranslation => "Missing Translation",
|
||||
ReportTranslationReason.IncorrectTranslation => "Incorrect Translation",
|
||||
ReportTranslationReason.ValuesNotFilledIntoString => "Values Missing in Strings",
|
||||
ReportTranslationReason.Other => "Other",
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
}
|
||||
|
||||
string GetType(ReportTranslationType type)
|
||||
{
|
||||
return Enum.GetName(typeof(ReportTranslationType), type);
|
||||
}
|
||||
|
||||
var issue = await ctx.Bot.GithubClient.Issue.Create(ctx.Bot.status.LoadedConfig.Secrets.Github.Username,
|
||||
ctx.Bot.status.LoadedConfig.Secrets.Github.Repository,
|
||||
new NewIssue($"{GetReason(reasonType)}: {component.FullSanitize()}")
|
||||
{
|
||||
Body =
|
||||
$"### Component Type: `{GetType(affectedType)}`\n" +
|
||||
$"### Affected Component: `{component.SanitizeForCode().Replace("@", "")}`\n" +
|
||||
$"```\n" +
|
||||
$"{additionalInformation?.Replace("@", "") ?? "No additional information supplied."}\n" +
|
||||
$"```\n" +
|
||||
$"</br></br></br>\n" +
|
||||
$"**Submission Details**\n" +
|
||||
$"</br>\n" +
|
||||
$"<img align=\"left\" style=\"align:center;\" width=\"32\" height=\"32\" src=\"{ctx.User.AvatarUrl}\"> [`{ctx.User.GetUsernameWithIdentifier().SanitizeForCode()}`]({ctx.User.AvatarUrl}) (`{ctx.User.Id}`)\n\n" +
|
||||
$"<img align=\"left\" style=\"align:center;\" width=\"32\" height=\"32\" src=\"{ctx.Guild.IconUrl}\"> [`{ctx.Guild.Name.SanitizeForCode()}`]({ctx.Guild.IconUrl}) (`{ctx.Guild.Id}`)\n"
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
_ = await ctx.Bot.GithubClient.Issue.Labels.ReplaceAllForIssue(ctx.Bot.status.LoadedConfig.Secrets.Github.Username, ctx.Bot.status.LoadedConfig.Secrets.Github.Repository, issue.Number, labels);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warning(ex, "Failed to update labels on reported issue");
|
||||
}
|
||||
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder()
|
||||
.WithDescription(this.GetString(CommandKey.ReportSubmitted, true))
|
||||
.AsSuccess(ctx, this.GetString(CommandKey.Title)));
|
||||
});
|
||||
}
|
||||
}
|
||||
64
ProjectMakoto/Commands/Utility/UploadCommand.cs
Normal file
64
ProjectMakoto/Commands/Utility/UploadCommand.cs
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
// 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
|
||||
|
||||
namespace ProjectMakoto.Commands;
|
||||
|
||||
internal sealed class UploadCommand : BaseCommand
|
||||
{
|
||||
public override Task ExecuteCommand(SharedCommandContext ctx, Dictionary<string, object> arguments)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
var attachment = (DiscordAttachment)arguments["file"];
|
||||
var stream = await new HttpClient().GetStreamAsync(attachment.Url);
|
||||
var filesize = attachment.FileSize ?? 0;
|
||||
|
||||
if (ctx.DbUser.PendingUserUpload is null)
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(this.t.Commands.Utility.Upload.NoInteraction, true)
|
||||
}.AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.DbUser.PendingUserUpload.InteractionHandled)
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(this.t.Commands.Utility.Upload.AlreadyUploaded, true)
|
||||
}.AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.DbUser.PendingUserUpload.TimeOut.GetTotalSecondsUntil() < 0)
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(this.t.Commands.Utility.Upload.TimedOut, true,
|
||||
new TVar("Timestamp", ctx.DbUser.PendingUserUpload.TimeOut.ToTimestamp()))
|
||||
}.AsError(ctx));
|
||||
ctx.DbUser.PendingUserUpload = null;
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.DbUser.PendingUserUpload.UploadedData = stream;
|
||||
ctx.DbUser.PendingUserUpload.FileSize = filesize;
|
||||
ctx.DbUser.PendingUserUpload.InteractionHandled = true;
|
||||
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(this.t.Commands.Utility.Upload.Uploaded, true)
|
||||
}.AsSuccess(ctx));
|
||||
|
||||
await Task.Delay(500);
|
||||
this.DeleteOrInvalidate();
|
||||
});
|
||||
}
|
||||
}
|
||||
133
ProjectMakoto/Commands/Utility/UrbanDictionaryCommand.cs
Normal file
133
ProjectMakoto/Commands/Utility/UrbanDictionaryCommand.cs
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
// 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
|
||||
|
||||
namespace ProjectMakoto.Commands;
|
||||
|
||||
internal sealed class UrbanDictionaryCommand : BaseCommand
|
||||
{
|
||||
public override Task ExecuteCommand(SharedCommandContext ctx, Dictionary<string, object> arguments)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
if (await ctx.DbUser.Cooldown.WaitForModerate(ctx, true))
|
||||
return;
|
||||
|
||||
var term = (string)arguments["term"];
|
||||
|
||||
if (!ctx.Channel.IsNsfw && ctx.CommandType != Enums.CommandType.ApplicationCommand)
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(this.t.Commands.Utility.UrbanDictionary.AdultContentError, true)
|
||||
}.AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
var Yes = new DiscordButtonComponent(ButtonStyle.Success, Guid.NewGuid().ToString(), this.GetString(this.t.Common.Yes), false, new DiscordComponentEmoji(true.ToEmote(ctx.Bot)));
|
||||
var No = new DiscordButtonComponent(ButtonStyle.Danger, Guid.NewGuid().ToString(), this.GetString(this.t.Common.No), false, new DiscordComponentEmoji(false.ToEmote(ctx.Bot)));
|
||||
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(this.t.Commands.Utility.UrbanDictionary.AdultContentWarning, true)
|
||||
}.AsAwaitingInput(ctx)).AddComponents(new List<DiscordComponent> { Yes, No }));
|
||||
|
||||
var Menu = await ctx.WaitForButtonAsync();
|
||||
|
||||
if (Menu.TimedOut)
|
||||
{
|
||||
this.ModifyToTimedOut();
|
||||
return;
|
||||
}
|
||||
|
||||
_ = Menu.Result.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
|
||||
|
||||
if (Menu.GetCustomId() == Yes.CustomId)
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(this.t.Commands.Utility.UrbanDictionary.LookingUp, true,
|
||||
new TVar("Term", term))
|
||||
}.AsLoading(ctx));
|
||||
|
||||
if (term.IsNullOrWhiteSpace())
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(this.t.Commands.Utility.UrbanDictionary.LookupFail, true,
|
||||
new TVar("Term", term))
|
||||
}.AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
HttpClient client = new();
|
||||
|
||||
string query;
|
||||
|
||||
using (var content = new FormUrlEncodedContent(new Dictionary<string, string>
|
||||
{
|
||||
{ "term", term },
|
||||
}))
|
||||
{
|
||||
query = await content.ReadAsStringAsync();
|
||||
}
|
||||
|
||||
var Response = await client.GetAsync($"https://api.urbandictionary.com/v0/define?{query}");
|
||||
|
||||
if (!Response.IsSuccessStatusCode)
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(this.t.Commands.Utility.UrbanDictionary.LookupFail, true,
|
||||
new TVar("Term", term))
|
||||
}.AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
List<UrbanDictionary.List> Definitions = null;
|
||||
|
||||
try
|
||||
{
|
||||
var rawDefinitions = JsonConvert.DeserializeObject<UrbanDictionary>(await Response.Content.ReadAsStringAsync());
|
||||
Definitions = rawDefinitions.list.ToList();
|
||||
Definitions.Sort((a, b) => b.RatingRatio.CompareTo(a.RatingRatio));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, string.Empty);
|
||||
}
|
||||
|
||||
if (!Definitions.IsNotNullAndNotEmpty())
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(this.t.Commands.Utility.UrbanDictionary.NotExist, true, new TVar("Term", term))
|
||||
}.AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
var embeds = Definitions.Take(3).Select(x => new DiscordEmbedBuilder
|
||||
{
|
||||
Title = $"**{x.word.Replace("**", "")}** - {this.GetString(this.t.Commands.Utility.UrbanDictionary.WrittenBy, new TVar("Author", x.author))}",
|
||||
Description = $"**{this.GetString(this.t.Commands.Utility.UrbanDictionary.Definition)}**\n\n" +
|
||||
$"{x.definition.Replace("[", "").Replace("]", "")}\n\n" +
|
||||
$"**{this.GetString(this.t.Commands.Utility.UrbanDictionary.Example)}**\n\n" +
|
||||
$"{x.example.Replace("[", "").Replace("]", "")}\n\n" +
|
||||
$"👍 `{x.thumbs_up}` | 👎 `{x.thumbs_down}` | 🕒 {Formatter.Timestamp(x.written_on, TimestampFormat.LongDateTime)}",
|
||||
Url = x.permalink
|
||||
}.AsInfo(ctx).Build()).ToList();
|
||||
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().AddEmbeds(embeds));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.DeleteOrInvalidate();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
234
ProjectMakoto/Commands/Utility/UserInfoCommand.cs
Normal file
234
ProjectMakoto/Commands/Utility/UserInfoCommand.cs
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
// 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
|
||||
|
||||
namespace ProjectMakoto.Commands;
|
||||
|
||||
internal sealed class UserInfoCommand : BaseCommand
|
||||
{
|
||||
public override Task ExecuteCommand(SharedCommandContext ctx, Dictionary<string, object> arguments)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
var victim = (DiscordUser)arguments["user"];
|
||||
|
||||
if (await ctx.DbUser.Cooldown.WaitForLight(ctx))
|
||||
return;
|
||||
|
||||
victim ??= ctx.User;
|
||||
|
||||
victim = await victim.GetFromApiAsync();
|
||||
|
||||
DiscordMember? bMember = null;
|
||||
|
||||
try
|
||||
{
|
||||
bMember = await ctx.Guild.GetMemberAsync(victim.Id);
|
||||
}
|
||||
catch { }
|
||||
|
||||
static string GetStatusIcon(UserStatus? status)
|
||||
{
|
||||
return status switch
|
||||
{
|
||||
UserStatus.Online => "🟢",
|
||||
UserStatus.DoNotDisturb => "🔴",
|
||||
UserStatus.Idle => "🟡",
|
||||
UserStatus.Streaming => "🟣",
|
||||
_ => "⚪",
|
||||
};
|
||||
}
|
||||
|
||||
var GenerateRoles = "";
|
||||
|
||||
if (bMember is not null)
|
||||
{
|
||||
GenerateRoles = bMember.Roles.Any() ? string.Join(", ", bMember.Roles.Select(x => x.Mention)) : this.GetString(this.t.Commands.Utility.UserInfo.NoRoles, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
GenerateRoles = ctx.DbGuild.Members[victim.Id].MemberRoles.Length > 0
|
||||
? string.Join(", ", ctx.DbGuild.Members[victim.Id].MemberRoles.Where(x => ctx.Guild.Roles.ContainsKey(x.Id)).Select(x => $"{ctx.Guild.GetRole(x.Id).Mention}"))
|
||||
: this.GetString(this.t.Commands.Utility.UserInfo.NoStoredRoles, true);
|
||||
}
|
||||
|
||||
var banList = await ctx.Guild.GetBansAsync();
|
||||
var isBanned = banList.Any(x => x.User.Id == victim.Id);
|
||||
var banDetails = (isBanned ? banList.First(x => x.User.Id == victim.Id) : null);
|
||||
|
||||
var builder = new DiscordMessageBuilder();
|
||||
|
||||
var embed = new DiscordEmbedBuilder()
|
||||
{
|
||||
Author = new DiscordEmbedBuilder.EmbedAuthor
|
||||
{
|
||||
Name = $"{(victim.IsBot ? $"[{(victim.IsSystem ?? false ? this.GetString(this.t.Commands.Utility.UserInfo.System) : $"{this.GetString(this.t.Commands.Utility.UserInfo.Bot)}{(victim.IsVerifiedBot ? "✅" : "❎")}")}] " : "")}{victim.GetUsernameWithIdentifier()}",
|
||||
Url = victim.ProfileUrl
|
||||
},
|
||||
Thumbnail = new DiscordEmbedBuilder.EmbedThumbnail
|
||||
{
|
||||
Url = (string.IsNullOrWhiteSpace(victim.AvatarUrl) ? "https://cdn.discordapp.com/attachments/712761268393738301/899051918037504040/QuestionMark.png" : victim.AvatarUrl)
|
||||
},
|
||||
Color = victim.BannerColor ?? new("2f3136"),
|
||||
ImageUrl = victim.BannerUrl,
|
||||
Footer = new DiscordEmbedBuilder.EmbedFooter
|
||||
{
|
||||
Text = $"User-Id: {victim.Id}"
|
||||
},
|
||||
Description = $"{(bMember is null ? $"{(ctx.DbGuild.Members[victim.Id].FirstJoinDate == DateTime.MinValue ? this.GetString(this.t.Commands.Utility.UserInfo.NeverJoined, true) : $"{(isBanned ? this.GetString(this.t.Commands.Utility.UserInfo.IsBanned, true) : this.GetString(this.t.Commands.Utility.UserInfo.JoinedBefore, true))}")}\n\n" : "")}" +
|
||||
$"{(ctx.Bot.globalBans.ContainsKey(victim.Id) ? $"💀 **{this.GetString(this.t.Commands.Utility.UserInfo.GlobalBanned, true)}**\n" : "")}" +
|
||||
$"{(ctx.Bot.status.TeamOwner == victim.Id ? $"👑 **{this.GetString(this.t.Commands.Utility.UserInfo.BotOwner, true)}**\n" : "")}" +
|
||||
$"{(ctx.Bot.status.TeamMembers.Contains(victim.Id) ? $"🔏 **{this.GetString(this.t.Commands.Utility.UserInfo.BotStaff, true)}**\n\n" : "")}" +
|
||||
$"{(bMember is not null && bMember.IsOwner ? $"✨ {this.GetString(this.t.Commands.Utility.UserInfo.Owner, true)}\n" : "")}" +
|
||||
$"{(victim.IsStaff ? $"📘 **{this.GetString(this.t.Commands.Utility.UserInfo.DiscordStaff, true)}**\n" : "")}" +
|
||||
$"{(victim.IsMod ? $"⚒ {this.GetString(this.t.Commands.Utility.UserInfo.CertifiedMod, true)}\n" : "")}" +
|
||||
$"{(victim.IsBotDev ? $"⌨ {this.GetString(this.t.Commands.Utility.UserInfo.VerifiedBotDeveloper, true)}\n" : "")}" +
|
||||
$"{(victim.IsPartner ? $"👥 {this.GetString(this.t.Commands.Utility.UserInfo.DiscordPartner, true)}\n" : "")}" +
|
||||
$"{(bMember is not null && bMember.IsPending.HasValue && bMember.IsPending.Value ? $"❗ {this.GetString(this.t.Commands.Utility.UserInfo.PendingMembership, true)}\n" : "")}" +
|
||||
$"\n**{(bMember is null ? $"{this.GetString(this.t.Commands.Utility.UserInfo.Roles)} ({this.GetString(this.t.Commands.Utility.UserInfo.Backup)})" : this.GetString(this.t.Commands.Utility.UserInfo.Roles))}**\n{GenerateRoles}"
|
||||
};
|
||||
|
||||
if (ctx.Bot.globalNotes.TryGetValue(victim.Id, out var globalNotes) && globalNotes.Notes.Length != 0)
|
||||
{
|
||||
_ = embed.AddField(new DiscordEmbedField(this.GetString(this.t.Commands.Utility.UserInfo.BotNotes), $"{string.Join("\n\n", ctx.Bot.globalNotes[victim.Id].Notes.Select(x => $"{x.Reason.FullSanitize()} - <@{x.Moderator}> {x.Timestamp.ToTimestamp()}"))}".TruncateWithIndication(512)));
|
||||
}
|
||||
|
||||
if (ctx.Bot.globalBans.TryGetValue(victim.Id, out var globalBanDetails))
|
||||
{
|
||||
var gBanMod = await ctx.Client.GetUserAsync(ctx.Bot.globalBans[victim.Id].Moderator);
|
||||
|
||||
_ = embed.AddField(new DiscordEmbedField(this.GetString(this.t.Commands.Utility.UserInfo.GlobalBanReason), $"`{((string.IsNullOrWhiteSpace(globalBanDetails.Reason) || globalBanDetails.Reason == "-") ? this.GetString(this.t.Commands.Utility.UserInfo.NoReason) : globalBanDetails.Reason).SanitizeForCode()}`", true));
|
||||
_ = embed.AddField(new DiscordEmbedField(this.GetString(this.t.Commands.Utility.UserInfo.GlobalBanMod), $"`{gBanMod.GetUsernameWithIdentifier()}`", true));
|
||||
_ = embed.AddField(new DiscordEmbedField(this.GetString(this.t.Commands.Utility.UserInfo.GlobalBanDate), $"{Formatter.Timestamp(globalBanDetails.Timestamp)} ({Formatter.Timestamp(globalBanDetails.Timestamp, TimestampFormat.LongDateTime)})", true));
|
||||
}
|
||||
|
||||
if (isBanned)
|
||||
_ = embed.AddField(new DiscordEmbedField(this.GetString(this.t.Commands.Utility.UserInfo.BanDetails), $"`{(string.IsNullOrWhiteSpace(banDetails?.Reason) ? this.GetString(this.t.Commands.Utility.UserInfo.NoReason) : $"{banDetails.Reason}")}`", false));
|
||||
|
||||
var InviterButtonAdded = false;
|
||||
|
||||
if (ctx.DbGuild.InviteTracker.Enabled)
|
||||
{
|
||||
_ = embed.AddField(new DiscordEmbedField(this.GetString(this.t.Commands.Utility.UserInfo.InvitedBy), $"{(ctx.DbGuild.Members[victim.Id].InviteTracker.Code.IsNullOrWhiteSpace() ? this.GetString(this.t.Commands.Utility.UserInfo.NoInviter, true) : $"<@{ctx.DbGuild.Members[victim.Id].InviteTracker.UserId}> (`{ctx.DbGuild.Members[victim.Id].InviteTracker.UserId}`)")}", true));
|
||||
_ = embed.AddField(new DiscordEmbedField(this.GetString(this.t.Commands.Utility.UserInfo.UsersInvited), $"`{(ctx.DbGuild.Members.Fetch().Where(b => b.Value.InviteTracker.UserId == victim.Id)).Count()}`", true));
|
||||
|
||||
if (!ctx.DbGuild.Members[victim.Id].InviteTracker.Code.IsNullOrWhiteSpace())
|
||||
{
|
||||
InviterButtonAdded = true;
|
||||
_ = builder.AddComponents(new DiscordButtonComponent(ButtonStyle.Secondary, $"userinfo-inviter", this.GetString(this.t.Commands.Utility.UserInfo.ShowProfileInviter), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("👤"))));
|
||||
}
|
||||
}
|
||||
|
||||
if (bMember is not null)
|
||||
_ = embed.AddField(new DiscordEmbedField(this.GetString(this.t.Commands.Utility.UserInfo.ServerJoinDate), $"{Formatter.Timestamp(bMember.JoinedAt, TimestampFormat.LongDateTime)}", true));
|
||||
else
|
||||
_ = embed.AddField(new DiscordEmbedField(this.GetString(this.t.Commands.Utility.UserInfo.ServerLeaveDate), (ctx.DbGuild.Members[victim.Id].LastLeaveDate != DateTime.MinValue ? $"{Formatter.Timestamp(ctx.DbGuild.Members[victim.Id].LastLeaveDate, TimestampFormat.LongDateTime)} ({Formatter.Timestamp(ctx.DbGuild.Members[victim.Id].LastLeaveDate)})" : this.GetString(this.t.Commands.Utility.UserInfo.NeverJoined, true)), true));
|
||||
|
||||
_ = embed.AddField(new DiscordEmbedField(this.GetString(this.t.Commands.Utility.UserInfo.FirstJoinDate), (ctx.DbGuild.Members[victim.Id].FirstJoinDate != DateTime.MinValue ? $"{Formatter.Timestamp(ctx.DbGuild.Members[victim.Id].FirstJoinDate, TimestampFormat.LongDateTime)} ({Formatter.Timestamp(ctx.DbGuild.Members[victim.Id].FirstJoinDate)})" : this.GetString(this.t.Commands.Utility.UserInfo.NeverJoined, true)), true));
|
||||
|
||||
_ = embed.AddField(new DiscordEmbedField(this.GetString(this.t.Commands.Utility.UserInfo.AccountCreationDate), $"{Formatter.Timestamp(victim.CreationTimestamp, TimestampFormat.LongDateTime)}", true));
|
||||
|
||||
if (bMember is not null && bMember.PremiumSince.HasValue)
|
||||
_ = embed.AddField(new DiscordEmbedField(this.GetString(this.t.Commands.Utility.UserInfo.ServerBoosterSince), $"{Formatter.Timestamp(bMember.PremiumSince.Value, TimestampFormat.LongDateTime)}", true));
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(victim.Pronouns))
|
||||
_ = embed.AddField(new DiscordEmbedField(this.GetString(this.t.Commands.Utility.UserInfo.Pronouns), $"`{victim.Pronouns}`", true));
|
||||
|
||||
if (victim.BannerColor is not null)
|
||||
_ = embed.AddField(new DiscordEmbedField(this.GetString(this.t.Commands.Utility.UserInfo.BannerColor), $"`{victim.BannerColor.Value}`", true));
|
||||
|
||||
string TranslatePresence(UserStatus status)
|
||||
{
|
||||
return status switch
|
||||
{
|
||||
UserStatus.Online => this.GetString(this.t.Commands.Utility.UserInfo.Online),
|
||||
UserStatus.Idle => this.GetString(this.t.Commands.Utility.UserInfo.Idle),
|
||||
UserStatus.DoNotDisturb => this.GetString(this.t.Commands.Utility.UserInfo.DoNotDisturb),
|
||||
UserStatus.Streaming => this.GetString(this.t.Commands.Utility.UserInfo.Streaming),
|
||||
UserStatus.Offline => this.GetString(this.t.Commands.Utility.UserInfo.Offline),
|
||||
UserStatus.Invisible => this.GetString(this.t.Commands.Utility.UserInfo.Offline),
|
||||
_ => status.ToString(),
|
||||
};
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (victim.Presence is not null)
|
||||
_ = embed.AddField(new DiscordEmbedField(this.GetString(this.t.Commands.Utility.UserInfo.Presence), $"{GetStatusIcon(victim.Presence.Status)} `{TranslatePresence(victim.Presence.Status)}`\n" +
|
||||
$" {GetStatusIcon(victim.Presence.ClientStatus.Desktop.HasValue ? victim.Presence.ClientStatus.Desktop.Value : UserStatus.Offline)} {this.GetString(this.t.Commands.Utility.UserInfo.Desktop, true)}\n" +
|
||||
$" {GetStatusIcon(victim.Presence.ClientStatus.Mobile.HasValue ? victim.Presence.ClientStatus.Mobile.Value : UserStatus.Offline)} {this.GetString(this.t.Commands.Utility.UserInfo.Mobile, true)}\n" +
|
||||
$" {GetStatusIcon(victim.Presence.ClientStatus.Web.HasValue ? victim.Presence.ClientStatus.Web.Value : UserStatus.Offline)} {this.GetString(this.t.Commands.Utility.UserInfo.Web, true)}\n\n", true));
|
||||
}
|
||||
catch { }
|
||||
|
||||
string TranslateActivity(ActivityType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
ActivityType.Playing => this.GetString(this.t.Commands.Utility.UserInfo.Playing),
|
||||
ActivityType.Streaming => this.GetString(this.t.Commands.Utility.UserInfo.Streaming),
|
||||
ActivityType.ListeningTo => this.GetString(this.t.Commands.Utility.UserInfo.ListeningTo),
|
||||
ActivityType.Watching => this.GetString(this.t.Commands.Utility.UserInfo.Watching),
|
||||
ActivityType.Competing => this.GetString(this.t.Commands.Utility.UserInfo.Competing),
|
||||
_ => type.ToString(),
|
||||
};
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (victim.Presence is not null && victim.Presence.Activities is not null && victim.Presence.Activities?.Count > 0)
|
||||
_ = embed.AddField(new DiscordEmbedField(this.GetString(this.t.Commands.Utility.UserInfo.Activities), string.Join("\n", victim.Presence.Activities.Select(x => $"{(x.ActivityType == ActivityType.Custom ? $"• {this.GetString(this.t.Commands.Utility.UserInfo.Status)}: `{x.CustomStatus.Emoji?.Name ?? "None"}`{(string.IsNullOrWhiteSpace(x.CustomStatus.Name) ? "" : $" {x.CustomStatus.Name}")}\n" : $"• {TranslateActivity(x.ActivityType)} {x.Name}")}")), true));
|
||||
}
|
||||
catch { }
|
||||
|
||||
if (bMember is not null && bMember.CommunicationDisabledUntil.HasValue && bMember.CommunicationDisabledUntil.Value.GetTotalSecondsUntil() > 0)
|
||||
_ = embed.AddField(new DiscordEmbedField(this.GetString(this.t.Commands.Utility.UserInfo.TimedOutUntil), $"{Formatter.Timestamp(bMember.CommunicationDisabledUntil.Value, TimestampFormat.LongDateTime)}", true));
|
||||
|
||||
_ = await this.RespondOrEdit(builder.WithEmbed(embed));
|
||||
|
||||
if (InviterButtonAdded)
|
||||
{
|
||||
_ = ctx.ResponseMessage.WaitForButtonAsync(ctx.User, TimeSpan.FromMinutes(15)).ContinueWith(async x =>
|
||||
{
|
||||
if (x.IsFaulted)
|
||||
return;
|
||||
|
||||
var e = x.Result;
|
||||
|
||||
if (e.TimedOut)
|
||||
{
|
||||
this.ModifyToTimedOut();
|
||||
return;
|
||||
}
|
||||
|
||||
_ = e.Result.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
|
||||
|
||||
DiscordUser newVictim;
|
||||
|
||||
try
|
||||
{
|
||||
newVictim = await ctx.Client.GetUserAsync(ctx.DbGuild.Members[victim.Id].InviteTracker.UserId);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
_ = e.Result.Interaction.CreateFollowupMessageAsync(new DiscordFollowupMessageBuilder()
|
||||
.AddEmbed(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.UserInfo.FetchUserError, true, new TVar("User", ctx.DbGuild.Members[victim.Id].InviteTracker.UserId))).AsError(ctx)));
|
||||
return;
|
||||
}
|
||||
|
||||
await this.ExecuteCommand(ctx, new Dictionary<string, object>
|
||||
{
|
||||
{ "victim", newVictim }
|
||||
});
|
||||
|
||||
return;
|
||||
}).Add(ctx.Bot, ctx);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
62
ProjectMakoto/Commands/Utility/VcCreator/BanCommand.cs
Normal file
62
ProjectMakoto/Commands/Utility/VcCreator/BanCommand.cs
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
// 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
|
||||
|
||||
namespace ProjectMakoto.Commands.VcCreator;
|
||||
|
||||
internal sealed class BanCommand : BaseCommand
|
||||
{
|
||||
public override Task ExecuteCommand(SharedCommandContext ctx, Dictionary<string, object> arguments)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
if (await ctx.DbUser.Cooldown.WaitForHeavy(ctx))
|
||||
return;
|
||||
|
||||
var victim = (DiscordMember)arguments["user"];
|
||||
var channel = ctx.Member.VoiceState?.Channel;
|
||||
|
||||
if (!ctx.DbGuild.VcCreator.CreatedChannels.Any(x => x.ChannelId == (channel?.Id ?? 0)))
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.NotAVccChannel, true)).AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.DbGuild.VcCreator.CreatedChannels[channel.Id].OwnerId != ctx.User.Id)
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.NotAVccChannelOwner, true)).AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!channel.Users.Any(x => x.Id == victim.Id))
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.VictimNotPresent, true,
|
||||
new TVar("User", victim.Mention))).AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.DbGuild.VcCreator.CreatedChannels[channel.Id].OwnerId == victim.Id)
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.Ban.CannotBanSelf, true)).AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.DbGuild.VcCreator.CreatedChannels[channel.Id].BannedUsers.Contains(victim.Id))
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.Ban.VictimAlreadyBanned, true,
|
||||
new TVar("User", victim.Mention))).AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.DbGuild.VcCreator.CreatedChannels[channel.Id].BannedUsers = ctx.DbGuild.VcCreator.CreatedChannels[channel.Id].BannedUsers.Add(victim.Id);
|
||||
await channel.AddOverwriteAsync(victim, deny: Permissions.UseVoice);
|
||||
await victim.DisconnectFromVoiceAsync();
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.Ban.VictimBanned, true, new TVar("User", victim.Mention))).AsError(ctx));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
// 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
|
||||
|
||||
namespace ProjectMakoto.Commands.VcCreator;
|
||||
|
||||
internal sealed class ChangeOwnerCommand : BaseCommand
|
||||
{
|
||||
public override Task ExecuteCommand(SharedCommandContext ctx, Dictionary<string, object> arguments)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
if (await ctx.DbUser.Cooldown.WaitForHeavy(ctx))
|
||||
return;
|
||||
|
||||
var victim = (DiscordMember)arguments["user"];
|
||||
var channel = ctx.Member.VoiceState?.Channel;
|
||||
|
||||
if (!ctx.DbGuild.VcCreator.CreatedChannels.Any(x => x.ChannelId == (channel?.Id ?? 0)))
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.NotAVccChannel, true)).AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.DbGuild.VcCreator.CreatedChannels[channel.Id].OwnerId != ctx.User.Id)
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.NotAVccChannelOwner, true)).AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
if (victim.IsBot)
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.VictimIsBot, true, new TVar("User", victim.Mention))).AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.DbGuild.VcCreator.CreatedChannels[channel.Id].OwnerId == victim.Id)
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.ChangeOwner.AlreadyOwner, true, new TVar("User", victim.Mention))).AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.DbGuild.VcCreator.CreatedChannels[channel.Id].OwnerId != ctx.User.Id)
|
||||
{
|
||||
if (ctx.Member.Permissions.HasPermission(Permissions.ManageChannels))
|
||||
{
|
||||
ctx.DbGuild.VcCreator.CreatedChannels[channel.Id].OwnerId = victim.Id;
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.ChangeOwner.ForceAssign, true, new TVar("User", victim.Mention))).AsSuccess(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.NotAVccChannelOwner, true)).AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.DbGuild.VcCreator.CreatedChannels[channel.Id].OwnerId = victim.Id;
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.ChangeOwner.Success, true, new TVar("User", victim.Mention))).AsSuccess(ctx));
|
||||
});
|
||||
}
|
||||
}
|
||||
39
ProjectMakoto/Commands/Utility/VcCreator/CloseCommand.cs
Normal file
39
ProjectMakoto/Commands/Utility/VcCreator/CloseCommand.cs
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
// 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
|
||||
|
||||
namespace ProjectMakoto.Commands.VcCreator;
|
||||
|
||||
internal sealed class CloseCommand : BaseCommand
|
||||
{
|
||||
public override Task ExecuteCommand(SharedCommandContext ctx, Dictionary<string, object> arguments)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
if (await ctx.DbUser.Cooldown.WaitForHeavy(ctx))
|
||||
return;
|
||||
|
||||
var channel = ctx.Member.VoiceState?.Channel;
|
||||
|
||||
if (!ctx.DbGuild.VcCreator.CreatedChannels.Any(x => x.ChannelId == (channel?.Id ?? 0)))
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.NotAVccChannel, true)).AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.DbGuild.VcCreator.CreatedChannels[channel.Id].OwnerId != ctx.User.Id)
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.NotAVccChannelOwner, true)).AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
await channel.ModifyAsync(x => x.PermissionOverwrites = channel.PermissionOverwrites.Merge(ctx.Guild.EveryoneRole, Permissions.None, Permissions.UseVoice));
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.Close.Success, true)).AsSuccess(ctx));
|
||||
});
|
||||
}
|
||||
}
|
||||
69
ProjectMakoto/Commands/Utility/VcCreator/InviteCommand.cs
Normal file
69
ProjectMakoto/Commands/Utility/VcCreator/InviteCommand.cs
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
// 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
|
||||
|
||||
namespace ProjectMakoto.Commands.VcCreator;
|
||||
|
||||
internal sealed class InviteCommand : BaseCommand
|
||||
{
|
||||
public override Task ExecuteCommand(SharedCommandContext ctx, Dictionary<string, object> arguments)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
if (await ctx.DbUser.Cooldown.WaitForHeavy(ctx))
|
||||
return;
|
||||
|
||||
var victim = (DiscordMember)arguments["user"];
|
||||
var channel = ctx.Member.VoiceState?.Channel;
|
||||
|
||||
if (!ctx.DbGuild.VcCreator.CreatedChannels.Any(x => x.ChannelId == (channel?.Id ?? 0)))
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.NotAVccChannel, true)).AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.DbGuild.VcCreator.CreatedChannels[channel.Id].OwnerId != ctx.User.Id)
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.NotAVccChannelOwner, true)).AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.DbGuild.VcCreator.CreatedChannels[channel.Id].OwnerId == victim.Id)
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.Invite.CannotInviteSelf, true)).AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
if (channel.Users.Any(x => x.Id == victim.Id))
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.Invite.AlreadyPresent, true, new TVar("User", victim.Mention))).AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
if (victim.IsBot)
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.VictimIsBot, true, new TVar("User", victim.Mention))).AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
await channel.AddOverwriteAsync(victim, Permissions.UseVoice);
|
||||
|
||||
try
|
||||
{
|
||||
_ = await victim.SendMessageAsync(this.t.Commands.Utility.VoiceChannelCreator.Invite.VictimMessage.Get(ctx.Bot.Users[victim.Id]).Build(new TVar("Channel", channel.Mention)));
|
||||
}
|
||||
catch (DisCatSharp.Exceptions.UnauthorizedException)
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.Invite.PartialSuccess, true, new TVar("User", victim.Mention))).AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.Invite.Success, true, new TVar("User", victim.Mention))).AsSuccess(ctx));
|
||||
});
|
||||
}
|
||||
}
|
||||
52
ProjectMakoto/Commands/Utility/VcCreator/KickCommand.cs
Normal file
52
ProjectMakoto/Commands/Utility/VcCreator/KickCommand.cs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
// 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
|
||||
|
||||
namespace ProjectMakoto.Commands.VcCreator;
|
||||
|
||||
internal sealed class KickCommand : BaseCommand
|
||||
{
|
||||
public override Task ExecuteCommand(SharedCommandContext ctx, Dictionary<string, object> arguments)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
if (await ctx.DbUser.Cooldown.WaitForHeavy(ctx))
|
||||
return;
|
||||
|
||||
var victim = (DiscordMember)arguments["user"];
|
||||
var channel = ctx.Member.VoiceState?.Channel;
|
||||
|
||||
if (!ctx.DbGuild.VcCreator.CreatedChannels.Any(x => x.ChannelId == (channel?.Id ?? 0)))
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.NotAVccChannel, true)).AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.DbGuild.VcCreator.CreatedChannels[channel.Id].OwnerId != ctx.User.Id)
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.NotAVccChannelOwner, true)).AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.DbGuild.VcCreator.CreatedChannels[channel.Id].OwnerId == victim.Id)
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.Kick.CannotKickSelf, true)).AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!channel.Users.Any(x => x.Id == victim.Id))
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.VictimNotPresent, true, new TVar("User", victim.Mention))).AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
await victim.DisconnectFromVoiceAsync();
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.Kick.Success, true, new TVar("User", victim.Mention))).AsSuccess(ctx));
|
||||
});
|
||||
}
|
||||
}
|
||||
46
ProjectMakoto/Commands/Utility/VcCreator/LimitCommand.cs
Normal file
46
ProjectMakoto/Commands/Utility/VcCreator/LimitCommand.cs
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
// 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
|
||||
|
||||
namespace ProjectMakoto.Commands.VcCreator;
|
||||
|
||||
internal sealed class LimitCommand : BaseCommand
|
||||
{
|
||||
public override Task ExecuteCommand(SharedCommandContext ctx, Dictionary<string, object> arguments)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
if (await ctx.DbUser.Cooldown.WaitForHeavy(ctx))
|
||||
return;
|
||||
|
||||
var newLimit = (uint)arguments["limit"];
|
||||
var channel = ctx.Member.VoiceState?.Channel;
|
||||
|
||||
if (!ctx.DbGuild.VcCreator.CreatedChannels.Any(x => x.ChannelId == (channel?.Id ?? 0)))
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.NotAVccChannel, true)).AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.DbGuild.VcCreator.CreatedChannels[channel.Id].OwnerId != ctx.User.Id)
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.NotAVccChannelOwner, true)).AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
if (newLimit > 99)
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.Limit.OutsideRange, true)).AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
await channel.ModifyAsync(x => x.UserLimit = newLimit.ToInt32());
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.Limit.Success, true, new TVar("Count", newLimit))).AsSuccess(ctx));
|
||||
});
|
||||
}
|
||||
}
|
||||
54
ProjectMakoto/Commands/Utility/VcCreator/NameCommand.cs
Normal file
54
ProjectMakoto/Commands/Utility/VcCreator/NameCommand.cs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
// 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
|
||||
|
||||
namespace ProjectMakoto.Commands.VcCreator;
|
||||
|
||||
internal sealed class NameCommand : BaseCommand
|
||||
{
|
||||
public override Task ExecuteCommand(SharedCommandContext ctx, Dictionary<string, object> arguments)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
if (await ctx.DbUser.Cooldown.WaitForHeavy(ctx))
|
||||
return;
|
||||
|
||||
var newName = (string)arguments["name"];
|
||||
var channel = ctx.Member.VoiceState?.Channel;
|
||||
|
||||
newName = (newName.IsNullOrWhiteSpace() ? this.GetGuildString(this.t.Commands.Utility.VoiceChannelCreator.Events.DefaultChannelName, new TVar("User", ctx.Member.DisplayName)) : newName);
|
||||
|
||||
if (!ctx.DbGuild.VcCreator.CreatedChannels.Any(x => x.ChannelId == (channel?.Id ?? 0)))
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.NotAVccChannel, true)).AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.DbGuild.VcCreator.CreatedChannels[channel.Id].OwnerId != ctx.User.Id)
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.NotAVccChannelOwner, true)).AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.DbGuild.VcCreator.CreatedChannels[channel.Id].LastRename.GetTimespanSince() < TimeSpan.FromMinutes(5))
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.Name.Cooldown, true,
|
||||
new TVar("Timestamp", ctx.DbGuild.VcCreator.CreatedChannels[channel.Id].LastRename.AddMinutes(5).ToTimestamp()))).AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var b in ctx.Bot.ProfanityList)
|
||||
newName = newName.Replace(b, new String('*', b.Length));
|
||||
|
||||
ctx.DbGuild.VcCreator.CreatedChannels[channel.Id].LastRename = DateTime.UtcNow;
|
||||
await channel.ModifyAsync(x => x.Name = newName.TruncateWithIndication(25));
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.Name.Success, true,
|
||||
new TVar("Name", newName, true))).AsSuccess(ctx));
|
||||
});
|
||||
}
|
||||
}
|
||||
39
ProjectMakoto/Commands/Utility/VcCreator/OpenCommand.cs
Normal file
39
ProjectMakoto/Commands/Utility/VcCreator/OpenCommand.cs
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
// 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
|
||||
|
||||
namespace ProjectMakoto.Commands.VcCreator;
|
||||
|
||||
internal sealed class OpenCommand : BaseCommand
|
||||
{
|
||||
public override Task ExecuteCommand(SharedCommandContext ctx, Dictionary<string, object> arguments)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
if (await ctx.DbUser.Cooldown.WaitForHeavy(ctx))
|
||||
return;
|
||||
|
||||
var channel = ctx.Member.VoiceState?.Channel;
|
||||
|
||||
if (!ctx.DbGuild.VcCreator.CreatedChannels.Any(x => x.ChannelId == (channel?.Id ?? 0)))
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.NotAVccChannel, true)).AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.DbGuild.VcCreator.CreatedChannels[channel.Id].OwnerId != ctx.User.Id)
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.NotAVccChannelOwner, true)).AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
await channel.ModifyAsync(x => x.PermissionOverwrites = channel.PermissionOverwrites.Merge(ctx.Guild.EveryoneRole, Permissions.None, Permissions.None, Permissions.UseVoice));
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.Open.Success, true)).AsSuccess(ctx));
|
||||
});
|
||||
}
|
||||
}
|
||||
47
ProjectMakoto/Commands/Utility/VcCreator/UnbanCommand.cs
Normal file
47
ProjectMakoto/Commands/Utility/VcCreator/UnbanCommand.cs
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
// 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
|
||||
|
||||
namespace ProjectMakoto.Commands.VcCreator;
|
||||
|
||||
internal sealed class UnbanCommand : BaseCommand
|
||||
{
|
||||
public override Task ExecuteCommand(SharedCommandContext ctx, Dictionary<string, object> arguments)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
if (await ctx.DbUser.Cooldown.WaitForHeavy(ctx))
|
||||
return;
|
||||
|
||||
var victim = (DiscordMember)arguments["user"];
|
||||
var channel = ctx.Member.VoiceState?.Channel;
|
||||
|
||||
if (!ctx.DbGuild.VcCreator.CreatedChannels.Any(x => x.ChannelId == (channel?.Id ?? 0)))
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.NotAVccChannel, true)).AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.DbGuild.VcCreator.CreatedChannels[channel.Id].OwnerId != ctx.User.Id)
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.NotAVccChannelOwner, true)).AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ctx.DbGuild.VcCreator.CreatedChannels[channel.Id].BannedUsers.Contains(victim.Id))
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.Unban.VictimNotBanned, true, new TVar("User", victim.Mention))).AsError(ctx));
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.DbGuild.VcCreator.CreatedChannels[channel.Id].BannedUsers = ctx.DbGuild.VcCreator.CreatedChannels[channel.Id].BannedUsers.Remove(x => x.ToString(), victim.Id);
|
||||
await channel.AddOverwriteAsync(victim, deny: Permissions.None);
|
||||
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().WithDescription(this.GetString(this.t.Commands.Utility.VoiceChannelCreator.Unban.VictimUnbanned, true, new TVar("User", victim.Mention))).AsSuccess(ctx));
|
||||
});
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue