This commit is contained in:
Caraxi 2025-08-22 18:33:14 +09:30
parent 616b96981d
commit bc1c884562
26 changed files with 209 additions and 498 deletions

View file

@ -117,8 +117,8 @@ internal class DiscordBot : IHostedService
_botServices.UpdateGuild(guild);
await _botServices.LogToChannel("Bot startup complete.").ConfigureAwait(false);
_ = UpdateVanityRoles(guild, _clientConnectedCts.Token);
_ = RemoveUsersNotInVanityRole(_clientConnectedCts.Token);
_ = RemoveUnregisteredUsers(_clientConnectedCts.Token);
// _ = RemoveUsersNotInVanityRole(_clientConnectedCts.Token);
// 1_ = RemoveUnregisteredUsers(_clientConnectedCts.Token);
}
private async Task UpdateVanityRoles(RestGuild guild, CancellationToken token)

View file

@ -1,215 +0,0 @@
using Discord;
using Discord.Interactions;
using MareSynchronosShared.Utils.Configuration;
using System.Text.Json;
namespace MareSynchronosServices.Discord;
public partial class MareWizardModule : InteractionModuleBase
{
private const int _totalAprilFoolsRoles = 200;
private const string _persistentFileName = "april2024.json";
private static readonly SemaphoreSlim _fileSemaphore = new(1, 1);
[ComponentInteraction("wizard-fools")]
public async Task ComponentFools()
{
if (!(await ValidateInteraction().ConfigureAwait(false))) return;
_logger.LogInformation("{method}:{userId}", nameof(ComponentFools), Context.Interaction.User.Id);
EmbedBuilder eb = new();
eb.WithTitle("WorryCoin™ and MareToken© Balance");
eb.WithColor(Color.Gold);
eb.WithDescription("You currently have" + Environment.NewLine + Environment.NewLine
+ "**200000** MaTE©" + Environment.NewLine
+ "**0** WorryCoin™" + Environment.NewLine + Environment.NewLine
+ "You have no payment method set up. Press the button below to add a payment method.");
ComponentBuilder cb = new();
AddHome(cb);
cb.WithButton("Add Payment Method", "wizard-fools-start", ButtonStyle.Primary, emote: new Emoji("💲"));
await ModifyInteraction(eb, cb).ConfigureAwait(false);
}
[ComponentInteraction("wizard-fools-start")]
public async Task ComponentFoolsStart()
{
if (!(await ValidateInteraction().ConfigureAwait(false))) return;
_logger.LogInformation("{method}:{userId}", nameof(ComponentFoolsStart), Context.Interaction.User.Id);
EmbedBuilder eb = new();
var user = await Context.Guild.GetUserAsync(Context.User.Id).ConfigureAwait(false);
bool userIsInPermanentVanityRole = _botServices.VanityRoles.Where(v => !v.Value.Contains('$', StringComparison.Ordinal))
.Select(v => v.Key).Any(u => user.RoleIds.Contains(u.Id)) || !_botServices.VanityRoles.Any();
ComponentBuilder cb = new();
AddHome(cb);
var participatedUsers = await GetParticipants().ConfigureAwait(false);
var remainingRoles = _totalAprilFoolsRoles - participatedUsers.Count(c => c.Value == true);
if (userIsInPermanentVanityRole)
{
eb.WithColor(Color.Green);
eb.WithTitle("Happy April Fools!");
eb.WithDescription("Thank you for participating in Mares 2024 April Fools event."
+ Environment.NewLine + Environment.NewLine
+ "As you might have already guessed from the post, nothing that was written there had any truth behind it."
+ Environment.NewLine + Environment.NewLine
+ "This entire thing was a jab at the ridiculousness of cryptocurrency, microtransactions and games featuring multiple currencies. I hope you enjoyed the announcement post!"
+ Environment.NewLine + Environment.NewLine
+ "__As you already have a role that gives you a permanent Vanity ID, you cannot win another one here. "
+ "However, tell your friends as this bot will give them a chance to win one of " + _totalAprilFoolsRoles + " lifetime vanity roles.__"
+ Environment.NewLine + Environment.NewLine
+ "The giveaway is active until <t:" + (new DateTime(2024, 04, 01, 23, 59, 59, DateTimeKind.Utc).Subtract(DateTime.UnixEpoch).TotalSeconds) + ":f>.");
}
else if (participatedUsers.ContainsKey(Context.User.Id))
{
eb.WithColor(Color.Orange);
eb.WithTitle("Happy April Fools!");
eb.WithDescription("Thank you for participating in Mares 2024 April Fools event."
+ Environment.NewLine + Environment.NewLine
+ "As you might have already guessed from the post, nothing that was written there had any truth behind it."
+ Environment.NewLine + Environment.NewLine
+ "This entire thing was a jab at the ridiculousness of cryptocurrency, microtransactions and games featuring multiple currencies. I hope you enjoyed the announcement post!"
+ Environment.NewLine + Environment.NewLine
+ "__You already participated in the giveaway of the permanent Vanity roles and therefore cannot participate again. Better luck next time!__");
}
else if (remainingRoles > 0)
{
eb.WithColor(Color.Green);
eb.WithTitle("Happy April Fools!");
eb.WithDescription("Thank you for participating in Mares 2024 April Fools event."
+ Environment.NewLine + Environment.NewLine
+ "As you might have already guessed from the post, nothing that was written there had any truth behind it."
+ Environment.NewLine + Environment.NewLine
+ "This entire thing was a jab at the ridiculousness of cryptocurrency, microtransactions and games featuring multiple currencies. I hope you enjoyed the announcement post!"
+ Environment.NewLine + Environment.NewLine
+ "You have currently no permanent role that allows you to set a Vanity ID, however I am giving away a total of " + _totalAprilFoolsRoles + " permanent vanity roles "
+ "(" + remainingRoles + " still remain) and you can win one using this bot!"
+ Environment.NewLine + Environment.NewLine
+ "To win you simply have to pick one of the buttons labeled \"Win\" below this post. Which button will win is random. "
+ "There is a 1 in 5 chance that you can win the role. __You can only participate once.__"
+ Environment.NewLine + Environment.NewLine
+ "The giveaway is active until <t:" + (new DateTime(2024, 04, 01, 23, 59, 59, DateTimeKind.Utc).Subtract(DateTime.UnixEpoch).TotalSeconds) + ":f>.");
cb.WithButton("Win", "wizard-fools-win:1", ButtonStyle.Primary, new Emoji("1⃣"));
cb.WithButton("Win", "wizard-fools-win:2", ButtonStyle.Primary, new Emoji("2⃣"));
cb.WithButton("Win", "wizard-fools-win:3", ButtonStyle.Primary, new Emoji("3⃣"));
cb.WithButton("Win", "wizard-fools-win:4", ButtonStyle.Primary, new Emoji("4⃣"));
cb.WithButton("Win", "wizard-fools-win:5", ButtonStyle.Primary, new Emoji("5⃣"));
}
else
{
eb.WithColor(Color.Orange);
eb.WithTitle("Happy April Fools!");
eb.WithDescription("Thank you for participating in Mares 2024 April Fools event."
+ Environment.NewLine + Environment.NewLine
+ "As you might have already guessed from the post, nothing that was written there had any truth behind it."
+ Environment.NewLine + Environment.NewLine
+ "This entire thing was a jab at the ridiculousness of cryptocurrency, microtransactions and games featuring multiple currencies. I hope you enjoyed the announcement post!"
+ Environment.NewLine + Environment.NewLine
+ "__I have been giving away " + _totalAprilFoolsRoles + " permanent Vanity ID roles for this server, however you are sadly too late as they ran out by now. "
+ "Better luck next year with whatever I will come up with!__");
}
await ModifyInteraction(eb, cb).ConfigureAwait(false);
}
[ComponentInteraction("wizard-fools-win:*")]
public async Task ComponentFoolsWin(int number)
{
if (!(await ValidateInteraction().ConfigureAwait(false))) return;
_logger.LogInformation("{method}:{userId}", nameof(ComponentFoolsWin), Context.Interaction.User.Id);
var winningNumber = new Random().Next(1, 6);
EmbedBuilder eb = new();
ComponentBuilder cb = new();
AddHome(cb);
bool hasWon = winningNumber == number;
await WriteParticipants(Context.Interaction.User.Id, hasWon).ConfigureAwait(false);
if (hasWon)
{
eb.WithColor(Color.Gold);
eb.WithTitle("Congratulations you are winner!");
eb.WithDescription("You, by pure accident and sheer luck, picked the right number and have won yourself a lifetime Vanity ID role on this server!"
+ Environment.NewLine + Environment.NewLine
+ "The role will remain as long as you remain on this server, if you happen to leave it you will not get the role back."
+ Environment.NewLine + Environment.NewLine
+ "Head over to Home and to the Vanity IDs section to set it up for your account!"
+ Environment.NewLine + Environment.NewLine
+ "Once again, thank you for participating and have a great day.");
var user = await Context.Guild.GetUserAsync(Context.User.Id).ConfigureAwait(false);
await user.AddRoleAsync(_mareServicesConfiguration.GetValue<ulong?>(nameof(ServicesConfiguration.DiscordRoleAprilFools2024)).Value).ConfigureAwait(false);
}
else
{
eb.WithColor(Color.Red);
eb.WithTitle("Fortune did not bless you");
eb.WithDescription("You, through sheer misfortune, sadly did not pick the right number. (The winning number was " + winningNumber + ")"
+ Environment.NewLine + Environment.NewLine
+ "Better luck next time!"
+ Environment.NewLine + Environment.NewLine
+ "Once again, thank you for participating and regardless, have a great day.");
}
await ModifyInteraction(eb, cb).ConfigureAwait(false);
}
private async Task<Dictionary<ulong, bool>> GetParticipants()
{
await _fileSemaphore.WaitAsync().ConfigureAwait(false);
try
{
if (!File.Exists(_persistentFileName))
{
return new();
}
var json = await File.ReadAllTextAsync(_persistentFileName).ConfigureAwait(false);
return JsonSerializer.Deserialize<Dictionary<ulong, bool>>(json);
}
catch
{
return new();
}
finally
{
_fileSemaphore.Release();
}
}
private async Task WriteParticipants(ulong participant, bool win)
{
await _fileSemaphore.WaitAsync().ConfigureAwait(false);
try
{
Dictionary<ulong, bool> participants = new();
if (File.Exists(_persistentFileName))
{
try
{
var json = await File.ReadAllTextAsync(_persistentFileName).ConfigureAwait(false);
participants = JsonSerializer.Deserialize<Dictionary<ulong, bool>>(json);
}
catch
{
// probably empty file just deal with it
}
}
participants[participant] = win;
await File.WriteAllTextAsync(_persistentFileName, JsonSerializer.Serialize(participants)).ConfigureAwait(false);
}
finally
{
_fileSemaphore.Release();
}
}
}

View file

@ -24,13 +24,14 @@ public partial class MareWizardModule
eb.WithColor(Color.Blue);
eb.WithTitle("Start Registration");
eb.WithDescription("Here you can start the registration process with the Mare Synchronos server of this Discord." + Environment.NewLine + Environment.NewLine
+ "- Have your Lodestone URL ready (i.e. https://eu.finalfantasyxiv.com/lodestone/character/XXXXXXXXX)" + Environment.NewLine
+ " - The registration requires you to modify your Lodestone profile with a generated code for verification" + Environment.NewLine
/*+ "- Have your Lodestone URL ready (i.e. https://eu.finalfantasyxiv.com/lodestone/character/XXXXXXXXX)" + Environment.NewLine
+ " - The registration requires you to modify your Lodestone profile with a generated code for verification" + Environment.NewLine*/
+ "- Do not use this on mobile because you will need to be able to copy the generated secret key" + Environment.NewLine
+ "# Follow the bot instructions precisely. Slow down and read.");
ComponentBuilder cb = new();
AddHome(cb);
cb.WithButton("Start Registration", "wizard-register-start", ButtonStyle.Primary, emote: new Emoji("🌒"));
cb.WithButton("Register", "wizard-register-verify-check:OK", ButtonStyle.Primary, emote: new Emoji("❓"));
// cb.WithButton("Start Registration", "wizard-register-start", ButtonStyle.Primary, emote: new Emoji("🌒"));
await ModifyInteraction(eb, cb).ConfigureAwait(false);
}
@ -97,79 +98,34 @@ public partial class MareWizardModule
public async Task ComponentRegisterVerifyCheck(string verificationCode)
{
if (!(await ValidateInteraction().ConfigureAwait(false))) return;
_logger.LogInformation("{method}:{userId}:{uid}", nameof(ComponentRegisterVerifyCheck), Context.Interaction.User.Id, verificationCode);
EmbedBuilder eb = new();
ComponentBuilder cb = new();
bool stillEnqueued = _botServices.VerificationQueue.Any(k => k.Key == Context.User.Id);
bool verificationRan = _botServices.DiscordVerifiedUsers.TryGetValue(Context.User.Id, out bool verified);
bool registerSuccess = false;
if (!verificationRan)
{
if (stillEnqueued)
{
eb.WithColor(Color.Gold);
eb.WithTitle("Your verification is still pending");
eb.WithDescription("Please try again and click Check in a few seconds");
cb.WithButton("Cancel", "wizard-register", ButtonStyle.Secondary, emote: new Emoji("❌"));
cb.WithButton("Check", "wizard-register-verify-check:" + verificationCode, ButtonStyle.Primary, emote: new Emoji("❓"));
}
else
{
eb.WithColor(Color.Red);
eb.WithTitle("Something went wrong");
eb.WithDescription("Your verification was processed but did not arrive properly. Please try to start the registration from the start.");
cb.WithButton("Restart", "wizard-register", ButtonStyle.Primary, emote: new Emoji("🔁"));
}
}
else
{
if (verified)
{
eb.WithColor(Color.Green);
using var db = await GetDbContext().ConfigureAwait(false);
var (uid, key) = await HandleAddUser(db).ConfigureAwait(false);
eb.WithTitle($"Registration successful, your UID: {uid}");
eb.WithDescription("This is your private secret key. Do not share this private secret key with anyone. **If you lose it, it is irrevocably lost.**"
+ Environment.NewLine + Environment.NewLine
+ "**__NOTE: Secret keys are considered legacy. Using the suggested OAuth2 authentication in Mare, you do not need to use this Secret Key.__**"
+ Environment.NewLine + Environment.NewLine
+ $"||**`{key}`**||"
+ Environment.NewLine + Environment.NewLine
+ "If you want to continue using legacy authentication, enter this key in Mare Synchronos and hit save to connect to the service."
+ Environment.NewLine
+ "__NOTE: The Secret Key only contains the letters ABCDEF and numbers 0 - 9.__"
+ Environment.NewLine
+ "You should connect as soon as possible to not get caught by the automatic cleanup process."
+ Environment.NewLine
+ "Have fun.");
AddHome(cb);
registerSuccess = true;
}
else
{
eb.WithColor(Color.Gold);
eb.WithTitle("Failed to verify registration");
eb.WithDescription("The bot was not able to find the required verification code on your Lodestone profile."
+ Environment.NewLine + Environment.NewLine
+ "Please restart your verification process, make sure to save your profile _twice_ for it to be properly saved."
+ Environment.NewLine + Environment.NewLine
+ "If this link does not lead to your profile edit page, you __need__ to configure the privacy settings first: https://na.finalfantasyxiv.com/lodestone/my/setting/profile/"
+ Environment.NewLine + Environment.NewLine
+ "**Make sure your profile is set to public (All Users) for your character. The bot cannot read profiles with privacy settings set to \"logged in\" or \"private\".**"
+ Environment.NewLine + Environment.NewLine
+ "## You __need__ to enter following the code this bot provided onto your Lodestone in the character profile:"
+ Environment.NewLine + Environment.NewLine
+ "**`" + verificationCode + "`**");
cb.WithButton("Cancel", "wizard-register", emote: new Emoji("❌"));
cb.WithButton("Retry", "wizard-register-verify:" + verificationCode, ButtonStyle.Primary, emote: new Emoji("🔁"));
}
}
eb.WithColor(Color.Green);
using var db = await GetDbContext().ConfigureAwait(false);
var (uid, key) = await HandleAddUser(db).ConfigureAwait(false);
eb.WithTitle($"Registration successful, your UID: {uid}");
eb.WithDescription("This is your private secret key. Do not share this private secret key with anyone. **If you lose it, it is irrevocably lost.**"
/*+ Environment.NewLine + Environment.NewLine
+ "**__NOTE: Secret keys are considered legacy. Using the suggested OAuth2 authentication in Mare, you do not need to use this Secret Key.__**"*/
+ Environment.NewLine + Environment.NewLine
+ $"**`{key}`**"
+ Environment.NewLine + Environment.NewLine
/*+ "If you want to continue using legacy authentication, enter this key in Mare Synchronos and hit save to connect to the service."
+ Environment.NewLine*/
+ "__NOTE: The Secret Key only contains the letters ABCDEF and numbers 0 - 9.__"
+ Environment.NewLine
//+ "You should connect as soon as possible to not get caught by the automatic cleanup process."
//+ Environment.NewLine
+ "Have fun.");
AddHome(cb);
await ModifyInteraction(eb, cb).ConfigureAwait(false);
if (registerSuccess)
await _botServices.AddRegisteredRoleAsync(Context.Interaction.User).ConfigureAwait(false);
// if (registerSuccess)await _botServices.AddRegisteredRoleAsync(Context.Interaction.User).ConfigureAwait(false);
}
private async Task<(bool, string)> HandleRegisterModalAsync(EmbedBuilder embed, LodestoneModal arg)
@ -262,8 +218,14 @@ public partial class MareWizardModule
private async Task<(string, string)> HandleAddUser(MareDbContext db)
{
_logger.LogWarning($"Adding User: {Context.User.Username}");
var lodestoneAuth = db.LodeStoneAuth.SingleOrDefault(u => u.DiscordId == Context.User.Id);
if (lodestoneAuth == null) {
lodestoneAuth = new LodeStoneAuth() { DiscordId = Context.User.Id, HashedLodestoneId = $"{Context.User.Id}", User = null, LodestoneAuthString = string.Empty };
await db.LodeStoneAuth.AddAsync(lodestoneAuth).ConfigureAwait(false);
}
var user = new User();
var hasValidUid = false;
@ -294,10 +256,12 @@ public partial class MareWizardModule
await db.Users.AddAsync(user).ConfigureAwait(false);
await db.Auth.AddAsync(auth).ConfigureAwait(false);
lodestoneAuth.StartedAt = null;
lodestoneAuth.User = user;
lodestoneAuth.LodestoneAuthString = null;
await db.SaveChangesAsync().ConfigureAwait(false);
_botServices.Logger.LogInformation("User registered: {userUID}:{hashedKey}", user.UID, hashedKey);

View file

@ -160,18 +160,17 @@ public partial class MareWizardModule : InteractionModuleBase
+ (!hasAccount ? string.Empty : ("- Check your account status press \" User Info\"" + Environment.NewLine))
+ (hasAccount ? string.Empty : ("- Register a new Mare Account press \"🌒 Register\"" + Environment.NewLine))
+ (!hasAccount ? string.Empty : ("- You lost your secret key press \"🏥 Recover\"" + Environment.NewLine))
+ (hasAccount ? string.Empty : ("- If you have changed your Discord account press \"🔗 Relink\"" + Environment.NewLine))
// + (hasAccount ? string.Empty : ("- If you have changed your Discord account press \"🔗 Relink\"" + Environment.NewLine))
+ (!hasAccount ? string.Empty : ("- Create a secondary UIDs press \"2⃣ Secondary UID\"" + Environment.NewLine))
+ (!hasAccount ? string.Empty : ("- Set a Vanity UID press \"💅 Vanity IDs\"" + Environment.NewLine))
+ (!hasAccount ? string.Empty : (!isInAprilFoolsMode ? string.Empty : ("- Check your WorryCoin™ and MareToken© balance and add payment options" + Environment.NewLine)))
+ (!hasAccount ? string.Empty : ("- Delete your primary or secondary accounts with \"⚠️ Delete\""))
);
eb.WithColor(Color.Blue);
ComponentBuilder cb = new();
if (!hasAccount)
{
cb.WithButton("Register", "wizard-register", ButtonStyle.Primary, new Emoji("🌒"));
cb.WithButton("Relink", "wizard-relink", ButtonStyle.Secondary, new Emoji("🔗"));
cb.WithButton("Register", "wizard-register-verify-check:OK", ButtonStyle.Primary, new Emoji("🌒"));
// cb.WithButton("Relink", "wizard-relink", ButtonStyle.Secondary, new Emoji("🔗"));
}
else
{
@ -179,10 +178,6 @@ public partial class MareWizardModule : InteractionModuleBase
cb.WithButton("Recover", "wizard-recover", ButtonStyle.Secondary, new Emoji("🏥"));
cb.WithButton("Secondary UID", "wizard-secondary", ButtonStyle.Secondary, new Emoji("2⃣"));
cb.WithButton("Vanity IDs", "wizard-vanity", ButtonStyle.Secondary, new Emoji("💅"));
if (isInAprilFoolsMode)
{
cb.WithButton("WorryCoin™ and MareToken© management", "wizard-fools", ButtonStyle.Primary, new Emoji("💲"));
}
cb.WithButton("Delete", "wizard-delete", ButtonStyle.Danger, new Emoji("⚠️"));
}