ProjectMakoto/ProjectMakoto/Commands/Utility/ReportTranslationCommand.cs

155 lines
No EOL
7.3 KiB
C#

// 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().AddEmbed(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)));
});
}
}