fix up some bot shit
This commit is contained in:
@@ -2,15 +2,10 @@
|
|||||||
using Discord.Interactions;
|
using Discord.Interactions;
|
||||||
using Discord.Rest;
|
using Discord.Rest;
|
||||||
using Discord.WebSocket;
|
using Discord.WebSocket;
|
||||||
using MareSynchronos.API.Data.Enum;
|
|
||||||
using MareSynchronos.API.Dto.User;
|
|
||||||
using MareSynchronos.API.SignalR;
|
|
||||||
using MareSynchronosServer.Hubs;
|
|
||||||
using MareSynchronosShared.Data;
|
using MareSynchronosShared.Data;
|
||||||
using MareSynchronosShared.Models;
|
using MareSynchronosShared.Models;
|
||||||
using MareSynchronosShared.Services;
|
using MareSynchronosShared.Services;
|
||||||
using MareSynchronosShared.Utils.Configuration;
|
using MareSynchronosShared.Utils.Configuration;
|
||||||
using Microsoft.AspNetCore.SignalR;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using StackExchange.Redis;
|
using StackExchange.Redis;
|
||||||
|
|
||||||
@@ -23,20 +18,20 @@ internal class DiscordBot : IHostedService
|
|||||||
private readonly IConnectionMultiplexer _connectionMultiplexer;
|
private readonly IConnectionMultiplexer _connectionMultiplexer;
|
||||||
private readonly DiscordSocketClient _discordClient;
|
private readonly DiscordSocketClient _discordClient;
|
||||||
private readonly ILogger<DiscordBot> _logger;
|
private readonly ILogger<DiscordBot> _logger;
|
||||||
private readonly IHubContext<MareHub> _mareHubContext;
|
private readonly IDbContextFactory<MareDbContext> _dbContextFactory;
|
||||||
private readonly IServiceProvider _services;
|
private readonly IServiceProvider _services;
|
||||||
private InteractionService _interactionModule;
|
private InteractionService _interactionModule;
|
||||||
private CancellationTokenSource? _processReportQueueCts;
|
private readonly CancellationTokenSource? _processReportQueueCts;
|
||||||
private CancellationTokenSource? _updateStatusCts;
|
private CancellationTokenSource? _updateStatusCts;
|
||||||
|
|
||||||
public DiscordBot(DiscordBotServices botServices, IServiceProvider services, IConfigurationService<ServicesConfiguration> configuration,
|
public DiscordBot(DiscordBotServices botServices, IServiceProvider services, IConfigurationService<ServicesConfiguration> configuration,
|
||||||
IHubContext<MareHub> mareHubContext,
|
IDbContextFactory<MareDbContext> dbContextFactory,
|
||||||
ILogger<DiscordBot> logger, IConnectionMultiplexer connectionMultiplexer)
|
ILogger<DiscordBot> logger, IConnectionMultiplexer connectionMultiplexer)
|
||||||
{
|
{
|
||||||
_botServices = botServices;
|
_botServices = botServices;
|
||||||
_services = services;
|
_services = services;
|
||||||
_configurationService = configuration;
|
_configurationService = configuration;
|
||||||
_mareHubContext = mareHubContext;
|
_dbContextFactory = dbContextFactory;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_connectionMultiplexer = connectionMultiplexer;
|
_connectionMultiplexer = connectionMultiplexer;
|
||||||
_discordClient = new(new DiscordSocketConfig()
|
_discordClient = new(new DiscordSocketConfig()
|
||||||
@@ -55,6 +50,7 @@ internal class DiscordBot : IHostedService
|
|||||||
_logger.LogInformation("Starting DiscordBot");
|
_logger.LogInformation("Starting DiscordBot");
|
||||||
_logger.LogInformation("Using Configuration: " + _configurationService.ToString());
|
_logger.LogInformation("Using Configuration: " + _configurationService.ToString());
|
||||||
|
|
||||||
|
_interactionModule?.Dispose();
|
||||||
_interactionModule = new InteractionService(_discordClient);
|
_interactionModule = new InteractionService(_discordClient);
|
||||||
_interactionModule.Log += Log;
|
_interactionModule.Log += Log;
|
||||||
await _interactionModule.AddModuleAsync(typeof(MareModule), _services).ConfigureAwait(false);
|
await _interactionModule.AddModuleAsync(typeof(MareModule), _services).ConfigureAwait(false);
|
||||||
@@ -64,7 +60,6 @@ internal class DiscordBot : IHostedService
|
|||||||
await _discordClient.StartAsync().ConfigureAwait(false);
|
await _discordClient.StartAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
_discordClient.Ready += DiscordClient_Ready;
|
_discordClient.Ready += DiscordClient_Ready;
|
||||||
_discordClient.ButtonExecuted += ButtonExecutedHandler;
|
|
||||||
_discordClient.InteractionCreated += async (x) =>
|
_discordClient.InteractionCreated += async (x) =>
|
||||||
{
|
{
|
||||||
var ctx = new SocketInteractionContext(_discordClient, x);
|
var ctx = new SocketInteractionContext(_discordClient, x);
|
||||||
@@ -79,124 +74,16 @@ internal class DiscordBot : IHostedService
|
|||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(_configurationService.GetValueOrDefault(nameof(ServicesConfiguration.DiscordBotToken), string.Empty)))
|
if (!string.IsNullOrEmpty(_configurationService.GetValueOrDefault(nameof(ServicesConfiguration.DiscordBotToken), string.Empty)))
|
||||||
{
|
{
|
||||||
_discordClient.ButtonExecuted -= ButtonExecutedHandler;
|
|
||||||
|
|
||||||
await _botServices.Stop().ConfigureAwait(false);
|
await _botServices.Stop().ConfigureAwait(false);
|
||||||
_processReportQueueCts?.Cancel();
|
_processReportQueueCts?.Cancel();
|
||||||
_updateStatusCts?.Cancel();
|
_updateStatusCts?.Cancel();
|
||||||
|
|
||||||
await _discordClient.LogoutAsync().ConfigureAwait(false);
|
await _discordClient.LogoutAsync().ConfigureAwait(false);
|
||||||
await _discordClient.StopAsync().ConfigureAwait(false);
|
await _discordClient.StopAsync().ConfigureAwait(false);
|
||||||
|
_interactionModule?.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ButtonExecutedHandler(SocketMessageComponent arg)
|
|
||||||
{
|
|
||||||
var id = arg.Data.CustomId;
|
|
||||||
if (!id.StartsWith("mare-report-button", StringComparison.Ordinal)) return;
|
|
||||||
|
|
||||||
var userId = arg.User.Id;
|
|
||||||
using var scope = _services.CreateScope();
|
|
||||||
using var dbContext = scope.ServiceProvider.GetRequiredService<MareDbContext>();
|
|
||||||
var user = await dbContext.LodeStoneAuth.Include(u => u.User).SingleOrDefaultAsync(u => u.DiscordId == userId).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (user == null || (!user.User.IsModerator && !user.User.IsAdmin))
|
|
||||||
{
|
|
||||||
EmbedBuilder eb = new();
|
|
||||||
eb.WithTitle($"Cannot resolve report");
|
|
||||||
eb.WithDescription($"<@{userId}>: You have no rights to resolve this report");
|
|
||||||
await arg.RespondAsync(embed: eb.Build()).ConfigureAwait(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
id = id.Remove(0, "mare-report-button-".Length);
|
|
||||||
var split = id.Split('-', StringSplitOptions.RemoveEmptyEntries);
|
|
||||||
|
|
||||||
var profile = await dbContext.UserProfileData.SingleAsync(u => u.UserUID == split[1]).ConfigureAwait(false);
|
|
||||||
|
|
||||||
var embed = arg.Message.Embeds.First();
|
|
||||||
|
|
||||||
var builder = embed.ToEmbedBuilder();
|
|
||||||
var otherPairs = await dbContext.ClientPairs.Where(p => p.UserUID == split[1]).Select(p => p.OtherUserUID).ToListAsync().ConfigureAwait(false);
|
|
||||||
switch (split[0])
|
|
||||||
{
|
|
||||||
case "dismiss":
|
|
||||||
builder.AddField("Resolution", $"Dismissed by <@{userId}>");
|
|
||||||
builder.WithColor(Color.Green);
|
|
||||||
profile.FlaggedForReport = false;
|
|
||||||
await _mareHubContext.Clients.User(split[1]).SendAsync(nameof(IMareHub.Client_ReceiveServerMessage),
|
|
||||||
MessageSeverity.Warning, "The Mare profile report against you has been evaluated and your profile re-enabled.")
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "banreporting":
|
|
||||||
builder.AddField("Resolution", $"Dismissed by <@{userId}>, Reporting user banned");
|
|
||||||
builder.WithColor(Color.DarkGreen);
|
|
||||||
profile.FlaggedForReport = false;
|
|
||||||
var reportingUser = await dbContext.Auth.SingleAsync(u => u.UserUID == split[2]).ConfigureAwait(false);
|
|
||||||
reportingUser.MarkForBan = true;
|
|
||||||
var regReporting = await dbContext.LodeStoneAuth.SingleAsync(u => u.User.UID == reportingUser.UserUID).ConfigureAwait(false);
|
|
||||||
dbContext.BannedRegistrations.Add(new MareSynchronosShared.Models.BannedRegistrations()
|
|
||||||
{
|
|
||||||
DiscordIdOrLodestoneAuth = regReporting.HashedLodestoneId
|
|
||||||
});
|
|
||||||
dbContext.BannedRegistrations.Add(new MareSynchronosShared.Models.BannedRegistrations()
|
|
||||||
{
|
|
||||||
DiscordIdOrLodestoneAuth = regReporting.DiscordId.ToString()
|
|
||||||
});
|
|
||||||
await _mareHubContext.Clients.User(split[1]).SendAsync(nameof(IMareHub.Client_ReceiveServerMessage),
|
|
||||||
MessageSeverity.Warning, "The Mare profile report against you has been evaluated and your profile re-enabled.")
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "banprofile":
|
|
||||||
builder.AddField("Resolution", $"Profile has been banned by <@{userId}>");
|
|
||||||
builder.WithColor(Color.Red);
|
|
||||||
profile.Base64ProfileImage = null;
|
|
||||||
profile.UserDescription = null;
|
|
||||||
profile.ProfileDisabled = true;
|
|
||||||
profile.FlaggedForReport = false;
|
|
||||||
await _mareHubContext.Clients.User(split[1]).SendAsync(nameof(IMareHub.Client_ReceiveServerMessage),
|
|
||||||
MessageSeverity.Warning, "The Mare profile report against you has been evaluated and the profile functionality permanently disabled.")
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "banuser":
|
|
||||||
builder.AddField("Resolution", $"User has been banned by <@{userId}>");
|
|
||||||
builder.WithColor(Color.DarkRed);
|
|
||||||
var offendingUser = await dbContext.Auth.SingleAsync(u => u.UserUID == split[1]).ConfigureAwait(false);
|
|
||||||
offendingUser.MarkForBan = true;
|
|
||||||
profile.Base64ProfileImage = null;
|
|
||||||
profile.UserDescription = null;
|
|
||||||
profile.ProfileDisabled = true;
|
|
||||||
var reg = await dbContext.LodeStoneAuth.SingleAsync(u => u.User.UID == offendingUser.UserUID).ConfigureAwait(false);
|
|
||||||
dbContext.BannedRegistrations.Add(new MareSynchronosShared.Models.BannedRegistrations()
|
|
||||||
{
|
|
||||||
DiscordIdOrLodestoneAuth = reg.HashedLodestoneId
|
|
||||||
});
|
|
||||||
dbContext.BannedRegistrations.Add(new MareSynchronosShared.Models.BannedRegistrations()
|
|
||||||
{
|
|
||||||
DiscordIdOrLodestoneAuth = reg.DiscordId.ToString()
|
|
||||||
});
|
|
||||||
await _mareHubContext.Clients.User(split[1]).SendAsync(nameof(IMareHub.Client_ReceiveServerMessage),
|
|
||||||
MessageSeverity.Warning, "The Mare profile report against you has been evaluated and your account permanently banned.")
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
await dbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
await _mareHubContext.Clients.Users(otherPairs).SendAsync(nameof(IMareHub.Client_UserUpdateProfile), new UserDto(new(split[1]))).ConfigureAwait(false);
|
|
||||||
await _mareHubContext.Clients.User(split[1]).SendAsync(nameof(IMareHub.Client_UserUpdateProfile), new UserDto(new(split[1]))).ConfigureAwait(false);
|
|
||||||
|
|
||||||
await arg.Message.ModifyAsync(msg =>
|
|
||||||
{
|
|
||||||
msg.Content = arg.Message.Content;
|
|
||||||
msg.Components = null;
|
|
||||||
msg.Embed = new Optional<Embed>(builder.Build());
|
|
||||||
}).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task DiscordClient_Ready()
|
private async Task DiscordClient_Ready()
|
||||||
{
|
{
|
||||||
var guild = (await _discordClient.Rest.GetGuildsAsync().ConfigureAwait(false)).First();
|
var guild = (await _discordClient.Rest.GetGuildsAsync().ConfigureAwait(false)).First();
|
||||||
@@ -229,7 +116,8 @@ internal class DiscordBot : IHostedService
|
|||||||
_logger.LogInformation("Adding Role: {id} => {desc}", role.Key, role.Value);
|
_logger.LogInformation("Adding Role: {id} => {desc}", role.Key, role.Value);
|
||||||
|
|
||||||
var restrole = guild.GetRole(role.Key);
|
var restrole = guild.GetRole(role.Key);
|
||||||
if (restrole != null) _botServices.VanityRoles.Add(restrole, role.Value);
|
if (restrole != null)
|
||||||
|
_botServices.VanityRoles[restrole] = role.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,7 +218,7 @@ internal class DiscordBot : IHostedService
|
|||||||
{
|
{
|
||||||
_logger.LogInformation($"Cleaning up Vanity UIDs");
|
_logger.LogInformation($"Cleaning up Vanity UIDs");
|
||||||
await _botServices.LogToChannel("Cleaning up Vanity UIDs").ConfigureAwait(false);
|
await _botServices.LogToChannel("Cleaning up Vanity UIDs").ConfigureAwait(false);
|
||||||
_logger.LogInformation("Getting application commands from guild {guildName}", guild.Name);
|
_logger.LogInformation("Getting rest guild {guildName}", guild.Name);
|
||||||
var restGuild = await _discordClient.Rest.GetGuildAsync(guild.Id).ConfigureAwait(false);
|
var restGuild = await _discordClient.Rest.GetGuildAsync(guild.Id).ConfigureAwait(false);
|
||||||
|
|
||||||
Dictionary<ulong, string> allowedRoleIds = _configurationService.GetValueOrDefault(nameof(ServicesConfiguration.VanityRoles), new Dictionary<ulong, string>());
|
Dictionary<ulong, string> allowedRoleIds = _configurationService.GetValueOrDefault(nameof(ServicesConfiguration.VanityRoles), new Dictionary<ulong, string>());
|
||||||
@@ -338,8 +226,7 @@ internal class DiscordBot : IHostedService
|
|||||||
|
|
||||||
if (allowedRoleIds.Any())
|
if (allowedRoleIds.Any())
|
||||||
{
|
{
|
||||||
await using var scope = _services.CreateAsyncScope();
|
using var db = await _dbContextFactory.CreateDbContextAsync().ConfigureAwait(false);
|
||||||
await using var db = scope.ServiceProvider.GetRequiredService<MareDbContext>();
|
|
||||||
|
|
||||||
var aliasedUsers = await db.LodeStoneAuth.Include("User")
|
var aliasedUsers = await db.LodeStoneAuth.Include("User")
|
||||||
.Where(c => c.User != null && !string.IsNullOrEmpty(c.User.Alias)).ToListAsync().ConfigureAwait(false);
|
.Where(c => c.User != null && !string.IsNullOrEmpty(c.User.Alias)).ToListAsync().ConfigureAwait(false);
|
||||||
@@ -347,6 +234,57 @@ internal class DiscordBot : IHostedService
|
|||||||
.Where(c => !string.IsNullOrEmpty(c.Alias)).ToListAsync().ConfigureAwait(false);
|
.Where(c => !string.IsNullOrEmpty(c.Alias)).ToListAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
foreach (var lodestoneAuth in aliasedUsers)
|
foreach (var lodestoneAuth in aliasedUsers)
|
||||||
|
{
|
||||||
|
await CheckVanityForUser(restGuild, allowedRoleIds, db, lodestoneAuth, token).ConfigureAwait(false);
|
||||||
|
|
||||||
|
await Task.Delay(1000, token).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var group in aliasedGroups)
|
||||||
|
{
|
||||||
|
await CheckVanityForGroup(restGuild, allowedRoleIds, db, group, token).ConfigureAwait(false);
|
||||||
|
|
||||||
|
await Task.Delay(1000, token).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogInformation("No roles for command defined, no cleanup performed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Something failed during checking vanity user uids");
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInformation("Vanity UID cleanup complete");
|
||||||
|
await Task.Delay(TimeSpan.FromHours(12), token).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CheckVanityForGroup(RestGuild restGuild, Dictionary<ulong, string> allowedRoleIds, MareDbContext db, Group group, CancellationToken token)
|
||||||
|
{
|
||||||
|
var lodestoneUser = await db.LodeStoneAuth.Include(u => u.User).SingleOrDefaultAsync(f => f.User.UID == group.OwnerUID).ConfigureAwait(false);
|
||||||
|
RestGuildUser discordUser = null;
|
||||||
|
if (lodestoneUser != null)
|
||||||
|
{
|
||||||
|
discordUser = await restGuild.GetUserAsync(lodestoneUser.DiscordId).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInformation($"Checking Group: {group.GID} [{group.Alias}], owned by {lodestoneUser?.User?.UID ?? string.Empty} ({lodestoneUser?.User?.Alias ?? string.Empty}), User in Roles: {string.Join(", ", discordUser?.RoleIds ?? new List<ulong>())}");
|
||||||
|
|
||||||
|
if (lodestoneUser == null || discordUser == null || !discordUser.RoleIds.Any(allowedRoleIds.Keys.Contains))
|
||||||
|
{
|
||||||
|
await _botServices.LogToChannel($"VANITY GID REMOVAL: <@{lodestoneUser?.DiscordId ?? 0}> ({lodestoneUser?.User?.UID}) - GID: {group.GID}, Vanity: {group.Alias}").ConfigureAwait(false);
|
||||||
|
|
||||||
|
_logger.LogInformation($"User {lodestoneUser?.User?.UID ?? "unknown"} not in allowed roles, deleting group alias for {group.GID}");
|
||||||
|
group.Alias = null;
|
||||||
|
db.Update(group);
|
||||||
|
await db.SaveChangesAsync(token).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CheckVanityForUser(RestGuild restGuild, Dictionary<ulong, string> allowedRoleIds, MareDbContext db, LodeStoneAuth lodestoneAuth, CancellationToken token)
|
||||||
{
|
{
|
||||||
var discordUser = await restGuild.GetUserAsync(lodestoneAuth.DiscordId).ConfigureAwait(false);
|
var discordUser = await restGuild.GetUserAsync(lodestoneAuth.DiscordId).ConfigureAwait(false);
|
||||||
_logger.LogInformation($"Checking User: {lodestoneAuth.DiscordId}, {lodestoneAuth.User.UID} ({lodestoneAuth.User.Alias}), User in Roles: {string.Join(", ", discordUser?.RoleIds ?? new List<ulong>())}");
|
_logger.LogInformation($"Checking User: {lodestoneAuth.DiscordId}, {lodestoneAuth.User.UID} ({lodestoneAuth.User.Alias}), User in Roles: {string.Join(", ", discordUser?.RoleIds ?? new List<ulong>())}");
|
||||||
@@ -367,47 +305,6 @@ internal class DiscordBot : IHostedService
|
|||||||
db.Update(lodestoneAuth.User);
|
db.Update(lodestoneAuth.User);
|
||||||
await db.SaveChangesAsync(token).ConfigureAwait(false);
|
await db.SaveChangesAsync(token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Task.Delay(1000, token).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var group in aliasedGroups)
|
|
||||||
{
|
|
||||||
var lodestoneUser = await db.LodeStoneAuth.Include(u => u.User).SingleOrDefaultAsync(f => f.User.UID == group.OwnerUID).ConfigureAwait(false);
|
|
||||||
RestGuildUser discordUser = null;
|
|
||||||
if (lodestoneUser != null)
|
|
||||||
{
|
|
||||||
discordUser = await restGuild.GetUserAsync(lodestoneUser.DiscordId).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.LogInformation($"Checking Group: {group.GID}, owned by {lodestoneUser?.User?.UID ?? string.Empty} ({lodestoneUser?.User?.Alias ?? string.Empty}), User in Roles: {string.Join(", ", discordUser?.RoleIds ?? new List<ulong>())}");
|
|
||||||
|
|
||||||
if (lodestoneUser == null || discordUser == null || !discordUser.RoleIds.Any(u => allowedRoleIds.Keys.Contains(u)))
|
|
||||||
{
|
|
||||||
await _botServices.LogToChannel($"VANITY GID REMOVAL: <@{lodestoneUser.DiscordId}> ({lodestoneUser.User.UID}) - GID: {group.GID}, Vanity: {group.Alias}").ConfigureAwait(false);
|
|
||||||
|
|
||||||
_logger.LogInformation($"User {lodestoneUser.User.UID} not in allowed roles, deleting group alias");
|
|
||||||
group.Alias = null;
|
|
||||||
db.Update(group);
|
|
||||||
await db.SaveChangesAsync(token).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
await Task.Delay(1000, token).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.LogInformation("No roles for command defined, no cleanup performed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Something failed during checking vanity user uids");
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.LogInformation("Vanity UID cleanup complete");
|
|
||||||
await Task.Delay(TimeSpan.FromHours(12), token).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task UpdateStatusAsync(CancellationToken token)
|
private async Task UpdateStatusAsync(CancellationToken token)
|
||||||
@@ -419,7 +316,7 @@ internal class DiscordBot : IHostedService
|
|||||||
|
|
||||||
_logger.LogInformation("Users online: " + onlineUsers);
|
_logger.LogInformation("Users online: " + onlineUsers);
|
||||||
await _discordClient.SetActivityAsync(new Game("Mare for " + onlineUsers + " Users")).ConfigureAwait(false);
|
await _discordClient.SetActivityAsync(new Game("Mare for " + onlineUsers + " Users")).ConfigureAwait(false);
|
||||||
await Task.Delay(TimeSpan.FromSeconds(15)).ConfigureAwait(false);
|
await Task.Delay(TimeSpan.FromSeconds(10)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,18 +8,17 @@ namespace MareSynchronosServices.Discord;
|
|||||||
|
|
||||||
public class DiscordBotServices
|
public class DiscordBotServices
|
||||||
{
|
{
|
||||||
public readonly string[] LodestoneServers = new[] { "eu", "na", "jp", "fr", "de" };
|
public readonly string[] LodestoneServers = ["eu", "na", "jp", "fr", "de"];
|
||||||
public ConcurrentDictionary<ulong, string> DiscordLodestoneMapping = new();
|
public ConcurrentDictionary<ulong, string> DiscordLodestoneMapping = new();
|
||||||
public ConcurrentDictionary<ulong, string> DiscordRelinkLodestoneMapping = new();
|
public ConcurrentDictionary<ulong, string> DiscordRelinkLodestoneMapping = new();
|
||||||
public ConcurrentDictionary<ulong, bool> DiscordVerifiedUsers { get; } = new();
|
public ConcurrentDictionary<ulong, bool> DiscordVerifiedUsers { get; } = new();
|
||||||
public ConcurrentDictionary<ulong, DateTime> LastVanityChange = new();
|
public ConcurrentDictionary<ulong, DateTime> LastVanityChange = new();
|
||||||
public ConcurrentDictionary<string, DateTime> LastVanityGidChange = new();
|
public ConcurrentDictionary<string, DateTime> LastVanityGidChange = new(StringComparer.Ordinal);
|
||||||
public ConcurrentDictionary<ulong, ulong> ValidInteractions { get; } = new();
|
public ConcurrentDictionary<ulong, ulong> ValidInteractions { get; } = new();
|
||||||
public Dictionary<RestRole, string> VanityRoles { get; set; } = new();
|
public ConcurrentDictionary<RestRole, string> VanityRoles { get; set; } = new();
|
||||||
public ConcurrentBag<ulong> VerifiedCaptchaUsers { get; } = new();
|
public ConcurrentBag<ulong> VerifiedCaptchaUsers { get; } = new();
|
||||||
private readonly IServiceProvider _serviceProvider;
|
|
||||||
private readonly IConfigurationService<ServicesConfiguration> _configuration;
|
private readonly IConfigurationService<ServicesConfiguration> _configuration;
|
||||||
private CancellationTokenSource verificationTaskCts;
|
private readonly CancellationTokenSource verificationTaskCts = new();
|
||||||
private RestGuild? _guild;
|
private RestGuild? _guild;
|
||||||
private ulong? _logChannelId;
|
private ulong? _logChannelId;
|
||||||
private RestTextChannel? _logChannel;
|
private RestTextChannel? _logChannel;
|
||||||
@@ -44,7 +43,8 @@ public class DiscordBotServices
|
|||||||
|
|
||||||
public Task Stop()
|
public Task Stop()
|
||||||
{
|
{
|
||||||
verificationTaskCts?.Cancel();
|
verificationTaskCts.Cancel();
|
||||||
|
verificationTaskCts.Dispose();
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,7 +73,6 @@ public class DiscordBotServices
|
|||||||
|
|
||||||
private async Task ProcessVerificationQueue()
|
private async Task ProcessVerificationQueue()
|
||||||
{
|
{
|
||||||
verificationTaskCts = new CancellationTokenSource();
|
|
||||||
while (!verificationTaskCts.IsCancellationRequested)
|
while (!verificationTaskCts.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
Logger.LogDebug("Processing Verification Queue, Entries: {entr}", VerificationQueue.Count);
|
Logger.LogDebug("Processing Verification Queue, Entries: {entr}", VerificationQueue.Count);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using Discord.Interactions;
|
using Discord.Interactions;
|
||||||
using Discord;
|
using Discord;
|
||||||
using MareSynchronosShared.Data;
|
|
||||||
using MareSynchronosShared.Utils;
|
using MareSynchronosShared.Utils;
|
||||||
using MareSynchronosShared.Utils.Configuration;
|
using MareSynchronosShared.Utils.Configuration;
|
||||||
|
|
||||||
@@ -15,7 +14,7 @@ public partial class MareWizardModule
|
|||||||
|
|
||||||
_logger.LogInformation("{method}:{userId}", nameof(ComponentDelete), Context.Interaction.User.Id);
|
_logger.LogInformation("{method}:{userId}", nameof(ComponentDelete), Context.Interaction.User.Id);
|
||||||
|
|
||||||
using var mareDb = GetDbContext();
|
using var mareDb = await GetDbContext().ConfigureAwait(false);
|
||||||
EmbedBuilder eb = new();
|
EmbedBuilder eb = new();
|
||||||
eb.WithTitle("Delete Account");
|
eb.WithTitle("Delete Account");
|
||||||
eb.WithDescription("You can delete your primary or secondary UIDs here." + Environment.NewLine + Environment.NewLine
|
eb.WithDescription("You can delete your primary or secondary UIDs here." + Environment.NewLine + Environment.NewLine
|
||||||
@@ -38,7 +37,7 @@ public partial class MareWizardModule
|
|||||||
|
|
||||||
_logger.LogInformation("{method}:{userId}:{uid}", nameof(SelectionDeleteAccount), Context.Interaction.User.Id, uid);
|
_logger.LogInformation("{method}:{userId}:{uid}", nameof(SelectionDeleteAccount), Context.Interaction.User.Id, uid);
|
||||||
|
|
||||||
using var mareDb = GetDbContext();
|
using var mareDb = await GetDbContext().ConfigureAwait(false);
|
||||||
bool isPrimary = mareDb.Auth.Single(u => u.UserUID == uid).PrimaryUserUID == null;
|
bool isPrimary = mareDb.Auth.Single(u => u.UserUID == uid).PrimaryUserUID == null;
|
||||||
EmbedBuilder eb = new();
|
EmbedBuilder eb = new();
|
||||||
eb.WithTitle($"Are you sure you want to delete {uid}?");
|
eb.WithTitle($"Are you sure you want to delete {uid}?");
|
||||||
@@ -88,7 +87,7 @@ public partial class MareWizardModule
|
|||||||
{
|
{
|
||||||
var maxGroupsByUser = _mareClientConfigurationService.GetValueOrDefault(nameof(ServerConfiguration.MaxGroupUserCount), 3);
|
var maxGroupsByUser = _mareClientConfigurationService.GetValueOrDefault(nameof(ServerConfiguration.MaxGroupUserCount), 3);
|
||||||
|
|
||||||
using var db = GetDbContext();
|
using var db = await GetDbContext().ConfigureAwait(false);
|
||||||
var user = db.Users.Single(u => u.UID == uid);
|
var user = db.Users.Single(u => u.UID == uid);
|
||||||
await SharedDbFunctions.PurgeUser(_logger, user, db, maxGroupsByUser).ConfigureAwait(false);
|
await SharedDbFunctions.PurgeUser(_logger, user, db, maxGroupsByUser).ConfigureAwait(false);
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ public partial class MareWizardModule
|
|||||||
|
|
||||||
_logger.LogInformation("{method}:{userId}", nameof(ComponentRecover), Context.Interaction.User.Id);
|
_logger.LogInformation("{method}:{userId}", nameof(ComponentRecover), Context.Interaction.User.Id);
|
||||||
|
|
||||||
using var mareDb = GetDbContext();
|
using var mareDb = await GetDbContext().ConfigureAwait(false);
|
||||||
EmbedBuilder eb = new();
|
EmbedBuilder eb = new();
|
||||||
eb.WithColor(Color.Blue);
|
eb.WithColor(Color.Blue);
|
||||||
eb.WithTitle("Recover");
|
eb.WithTitle("Recover");
|
||||||
@@ -25,7 +25,8 @@ public partial class MareWizardModule
|
|||||||
+ "Use the selection below to select the user account you want to recover." + Environment.NewLine + Environment.NewLine
|
+ "Use the selection below to select the user account you want to recover." + Environment.NewLine + Environment.NewLine
|
||||||
+ "- 1️⃣ is your primary account/UID" + Environment.NewLine
|
+ "- 1️⃣ is your primary account/UID" + Environment.NewLine
|
||||||
+ "- 2️⃣ are all your secondary accounts/UIDs" + Environment.NewLine
|
+ "- 2️⃣ are all your secondary accounts/UIDs" + Environment.NewLine
|
||||||
+ "If you are using Vanity UIDs the original UID is displayed in the second line of the account selection.");
|
+ "If you are using Vanity UIDs the original UID is displayed in the second line of the account selection." + Environment.NewLine
|
||||||
|
+ "# Note: instead of recovery and handling secret keys the switch to OAuth2 authentication is strongly suggested.");
|
||||||
ComponentBuilder cb = new();
|
ComponentBuilder cb = new();
|
||||||
await AddUserSelection(mareDb, cb, "wizard-recover-select").ConfigureAwait(false);
|
await AddUserSelection(mareDb, cb, "wizard-recover-select").ConfigureAwait(false);
|
||||||
AddHome(cb);
|
AddHome(cb);
|
||||||
@@ -39,7 +40,7 @@ public partial class MareWizardModule
|
|||||||
|
|
||||||
_logger.LogInformation("{method}:{userId}:{uid}", nameof(SelectionRecovery), Context.Interaction.User.Id, uid);
|
_logger.LogInformation("{method}:{userId}:{uid}", nameof(SelectionRecovery), Context.Interaction.User.Id, uid);
|
||||||
|
|
||||||
using var mareDb = GetDbContext();
|
using var mareDb = await GetDbContext().ConfigureAwait(false);
|
||||||
EmbedBuilder eb = new();
|
EmbedBuilder eb = new();
|
||||||
eb.WithColor(Color.Green);
|
eb.WithColor(Color.Green);
|
||||||
await HandleRecovery(mareDb, eb, uid).ConfigureAwait(false);
|
await HandleRecovery(mareDb, eb, uid).ConfigureAwait(false);
|
||||||
@@ -75,6 +76,8 @@ public partial class MareWizardModule
|
|||||||
+ $"**{computedHash}**"
|
+ $"**{computedHash}**"
|
||||||
+ Environment.NewLine
|
+ Environment.NewLine
|
||||||
+ "__NOTE: The Secret Key only contains the letters ABCDEF and numbers 0 - 9.__"
|
+ "__NOTE: The Secret Key only contains the letters ABCDEF and numbers 0 - 9.__"
|
||||||
|
+ Environment.NewLine
|
||||||
|
+" __NOTE: If you are using the suggested OAuth2 authentication, you do not need to use the Secret Key__"
|
||||||
+ Environment.NewLine + Environment.NewLine
|
+ Environment.NewLine + Environment.NewLine
|
||||||
+ "Enter this key in the Mare Synchronos Service Settings and reconnect to the service.");
|
+ "Enter this key in the Mare Synchronos Service Settings and reconnect to the service.");
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ public partial class MareWizardModule
|
|||||||
eb.WithDescription("Here you can start the registration process with the Mare Synchronos server of this Discord." + Environment.NewLine + Environment.NewLine
|
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
|
+ "- 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
|
+ " - The registration requires you to modify your Lodestone profile with a generated code for verification" + Environment.NewLine
|
||||||
+ " - You need to have a paid FFXIV account or someone who can assist you with registration if you can't edit your own Lodestone" + Environment.NewLine
|
+ "- Do not use this on mobile because you will need to be able to copy the generated secret key" + 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();
|
ComponentBuilder cb = new();
|
||||||
AddHome(cb);
|
AddHome(cb);
|
||||||
cb.WithButton("Start Registration", "wizard-register-start", ButtonStyle.Primary, emote: new Emoji("🌒"));
|
cb.WithButton("Start Registration", "wizard-register-start", ButtonStyle.Primary, emote: new Emoji("🌒"));
|
||||||
@@ -37,7 +37,7 @@ public partial class MareWizardModule
|
|||||||
|
|
||||||
_logger.LogInformation("{method}:{userId}", nameof(ComponentRegisterStart), Context.Interaction.User.Id);
|
_logger.LogInformation("{method}:{userId}", nameof(ComponentRegisterStart), Context.Interaction.User.Id);
|
||||||
|
|
||||||
using var db = GetDbContext();
|
using var db = await GetDbContext().ConfigureAwait(false);
|
||||||
var entry = await db.LodeStoneAuth.SingleOrDefaultAsync(u => u.DiscordId == Context.User.Id && u.StartedAt != null).ConfigureAwait(false);
|
var entry = await db.LodeStoneAuth.SingleOrDefaultAsync(u => u.DiscordId == Context.User.Id && u.StartedAt != null).ConfigureAwait(false);
|
||||||
if (entry != null)
|
if (entry != null)
|
||||||
{
|
{
|
||||||
@@ -123,7 +123,7 @@ public partial class MareWizardModule
|
|||||||
if (verified)
|
if (verified)
|
||||||
{
|
{
|
||||||
eb.WithColor(Color.Green);
|
eb.WithColor(Color.Green);
|
||||||
using var db = _services.CreateScope().ServiceProvider.GetRequiredService<MareDbContext>();
|
using var db = await GetDbContext().ConfigureAwait(false);
|
||||||
var (uid, key) = await HandleAddUser(db).ConfigureAwait(false);
|
var (uid, key) = await HandleAddUser(db).ConfigureAwait(false);
|
||||||
eb.WithTitle($"Registration successful, your UID: {uid}");
|
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.**"
|
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.**"
|
||||||
@@ -134,6 +134,8 @@ public partial class MareWizardModule
|
|||||||
+ Environment.NewLine
|
+ Environment.NewLine
|
||||||
+ "__NOTE: The Secret Key only contains the letters ABCDEF and numbers 0 - 9.__"
|
+ "__NOTE: The Secret Key only contains the letters ABCDEF and numbers 0 - 9.__"
|
||||||
+ Environment.NewLine
|
+ Environment.NewLine
|
||||||
|
+ " __NOTE: Secret keys are considered legacy. Using the suggested OAuth2 authentication, you do not need to use this Secret Key.__"
|
||||||
|
+ Environment.NewLine
|
||||||
+ "You should connect as soon as possible to not get caught by the automatic cleanup process."
|
+ "You should connect as soon as possible to not get caught by the automatic cleanup process."
|
||||||
+ Environment.NewLine
|
+ Environment.NewLine
|
||||||
+ "Have fun.");
|
+ "Have fun.");
|
||||||
@@ -143,10 +145,16 @@ public partial class MareWizardModule
|
|||||||
{
|
{
|
||||||
eb.WithColor(Color.Gold);
|
eb.WithColor(Color.Gold);
|
||||||
eb.WithTitle("Failed to verify registration");
|
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
|
eb.WithDescription("The bot was not able to find the required verification code on your Lodestone profile."
|
||||||
+ "Please restart your verification process, make sure to save your profile _twice_ for it to be properly saved." + Environment.NewLine + Environment.NewLine
|
+ 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
|
+ "Please restart your verification process, make sure to save your profile _twice_ for it to be properly saved."
|
||||||
+ "The code the bot is looking for is" + Environment.NewLine + Environment.NewLine
|
+ 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 + "**");
|
+ "**" + verificationCode + "**");
|
||||||
cb.WithButton("Cancel", "wizard-register", emote: new Emoji("❌"));
|
cb.WithButton("Cancel", "wizard-register", emote: new Emoji("❌"));
|
||||||
cb.WithButton("Retry", "wizard-register-verify:" + verificationCode, ButtonStyle.Primary, emote: new Emoji("🔁"));
|
cb.WithButton("Retry", "wizard-register-verify:" + verificationCode, ButtonStyle.Primary, emote: new Emoji("🔁"));
|
||||||
@@ -168,11 +176,9 @@ public partial class MareWizardModule
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check if userid is already in db
|
// check if userid is already in db
|
||||||
using var scope = _services.CreateScope();
|
|
||||||
|
|
||||||
var hashedLodestoneId = StringUtils.Sha256String(lodestoneId.ToString());
|
var hashedLodestoneId = StringUtils.Sha256String(lodestoneId.ToString());
|
||||||
|
|
||||||
using var db = scope.ServiceProvider.GetService<MareDbContext>();
|
using var db = await GetDbContext().ConfigureAwait(false);
|
||||||
|
|
||||||
// check if discord id or lodestone id is banned
|
// check if discord id or lodestone id is banned
|
||||||
if (db.BannedRegistrations.Any(a => a.DiscordIdOrLodestoneAuth == hashedLodestoneId))
|
if (db.BannedRegistrations.Any(a => a.DiscordIdOrLodestoneAuth == hashedLodestoneId))
|
||||||
@@ -192,6 +198,8 @@ public partial class MareWizardModule
|
|||||||
// check if lodestone id is already in db
|
// check if lodestone id is already in db
|
||||||
embed.WithTitle("Authorize your character");
|
embed.WithTitle("Authorize your character");
|
||||||
embed.WithDescription("Add following key to your character profile at https://na.finalfantasyxiv.com/lodestone/my/setting/profile/"
|
embed.WithDescription("Add following key to your character profile at https://na.finalfantasyxiv.com/lodestone/my/setting/profile/"
|
||||||
|
+ Environment.NewLine
|
||||||
|
+ "__NOTE: If the link does not lead you to your character edit profile page, you need to log in and set up your privacy settings!__"
|
||||||
+ Environment.NewLine + Environment.NewLine
|
+ Environment.NewLine + Environment.NewLine
|
||||||
+ $"**{lodestoneAuth}**"
|
+ $"**{lodestoneAuth}**"
|
||||||
+ Environment.NewLine + Environment.NewLine
|
+ Environment.NewLine + Environment.NewLine
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ using MareSynchronosShared.Data;
|
|||||||
using MareSynchronosShared.Utils;
|
using MareSynchronosShared.Utils;
|
||||||
using MareSynchronosShared.Models;
|
using MareSynchronosShared.Models;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using System.Security.Policy;
|
|
||||||
|
|
||||||
namespace MareSynchronosServices.Discord;
|
namespace MareSynchronosServices.Discord;
|
||||||
|
|
||||||
@@ -37,7 +36,7 @@ public partial class MareWizardModule
|
|||||||
|
|
||||||
_logger.LogInformation("{method}:{userId}", nameof(ComponentRelinkStart), Context.Interaction.User.Id);
|
_logger.LogInformation("{method}:{userId}", nameof(ComponentRelinkStart), Context.Interaction.User.Id);
|
||||||
|
|
||||||
using var db = GetDbContext();
|
using var db = await GetDbContext().ConfigureAwait(false);
|
||||||
db.LodeStoneAuth.RemoveRange(db.LodeStoneAuth.Where(u => u.DiscordId == Context.User.Id));
|
db.LodeStoneAuth.RemoveRange(db.LodeStoneAuth.Where(u => u.DiscordId == Context.User.Id));
|
||||||
_botServices.DiscordVerifiedUsers.TryRemove(Context.User.Id, out _);
|
_botServices.DiscordVerifiedUsers.TryRemove(Context.User.Id, out _);
|
||||||
_botServices.DiscordRelinkLodestoneMapping.TryRemove(Context.User.Id, out _);
|
_botServices.DiscordRelinkLodestoneMapping.TryRemove(Context.User.Id, out _);
|
||||||
@@ -119,7 +118,7 @@ public partial class MareWizardModule
|
|||||||
if (verified)
|
if (verified)
|
||||||
{
|
{
|
||||||
eb.WithColor(Color.Green);
|
eb.WithColor(Color.Green);
|
||||||
using var db = _services.CreateScope().ServiceProvider.GetRequiredService<MareDbContext>();
|
using var db = await GetDbContext().ConfigureAwait(false);
|
||||||
var (_, key) = await HandleRelinkUser(db, uid).ConfigureAwait(false);
|
var (_, key) = await HandleRelinkUser(db, uid).ConfigureAwait(false);
|
||||||
eb.WithTitle($"Relink successful, your UID is again: {uid}");
|
eb.WithTitle($"Relink successful, your UID is again: {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.**"
|
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.**"
|
||||||
@@ -161,11 +160,9 @@ public partial class MareWizardModule
|
|||||||
return (false, string.Empty, string.Empty);
|
return (false, string.Empty, string.Empty);
|
||||||
}
|
}
|
||||||
// check if userid is already in db
|
// check if userid is already in db
|
||||||
using var scope = _services.CreateScope();
|
|
||||||
|
|
||||||
var hashedLodestoneId = StringUtils.Sha256String(lodestoneId.ToString());
|
var hashedLodestoneId = StringUtils.Sha256String(lodestoneId.ToString());
|
||||||
|
|
||||||
using var db = scope.ServiceProvider.GetService<MareDbContext>();
|
using var db = await GetDbContext().ConfigureAwait(false);
|
||||||
|
|
||||||
// check if discord id or lodestone id is banned
|
// check if discord id or lodestone id is banned
|
||||||
if (db.BannedRegistrations.Any(a => a.DiscordIdOrLodestoneAuth == hashedLodestoneId))
|
if (db.BannedRegistrations.Any(a => a.DiscordIdOrLodestoneAuth == hashedLodestoneId))
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ public partial class MareWizardModule
|
|||||||
|
|
||||||
_logger.LogInformation("{method}:{userId}", nameof(ComponentSecondary), Context.Interaction.User.Id);
|
_logger.LogInformation("{method}:{userId}", nameof(ComponentSecondary), Context.Interaction.User.Id);
|
||||||
|
|
||||||
using var mareDb = GetDbContext();
|
using var mareDb = await GetDbContext().ConfigureAwait(false);
|
||||||
var primaryUID = (await mareDb.LodeStoneAuth.Include(u => u.User).SingleAsync(u => u.DiscordId == Context.User.Id).ConfigureAwait(false)).User.UID;
|
var primaryUID = (await mareDb.LodeStoneAuth.Include(u => u.User).SingleAsync(u => u.DiscordId == Context.User.Id).ConfigureAwait(false)).User.UID;
|
||||||
var secondaryUids = await mareDb.Auth.CountAsync(p => p.PrimaryUserUID == primaryUID).ConfigureAwait(false);
|
var secondaryUids = await mareDb.Auth.CountAsync(p => p.PrimaryUserUID == primaryUID).ConfigureAwait(false);
|
||||||
EmbedBuilder eb = new();
|
EmbedBuilder eb = new();
|
||||||
@@ -40,7 +40,7 @@ public partial class MareWizardModule
|
|||||||
|
|
||||||
_logger.LogInformation("{method}:{userId}:{primary}", nameof(ComponentSecondaryCreate), Context.Interaction.User.Id, primaryUid);
|
_logger.LogInformation("{method}:{userId}:{primary}", nameof(ComponentSecondaryCreate), Context.Interaction.User.Id, primaryUid);
|
||||||
|
|
||||||
using var mareDb = GetDbContext();
|
using var mareDb = await GetDbContext().ConfigureAwait(false);
|
||||||
EmbedBuilder eb = new();
|
EmbedBuilder eb = new();
|
||||||
eb.WithTitle("Secondary UID created");
|
eb.WithTitle("Secondary UID created");
|
||||||
eb.WithColor(Color.Green);
|
eb.WithColor(Color.Green);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ public partial class MareWizardModule
|
|||||||
|
|
||||||
_logger.LogInformation("{method}:{userId}", nameof(ComponentUserinfo), Context.Interaction.User.Id);
|
_logger.LogInformation("{method}:{userId}", nameof(ComponentUserinfo), Context.Interaction.User.Id);
|
||||||
|
|
||||||
using var mareDb = GetDbContext();
|
using var mareDb = await GetDbContext().ConfigureAwait(false);
|
||||||
EmbedBuilder eb = new();
|
EmbedBuilder eb = new();
|
||||||
eb.WithTitle("User Info");
|
eb.WithTitle("User Info");
|
||||||
eb.WithColor(Color.Blue);
|
eb.WithColor(Color.Blue);
|
||||||
@@ -36,7 +36,7 @@ public partial class MareWizardModule
|
|||||||
|
|
||||||
_logger.LogInformation("{method}:{userId}:{uid}", nameof(SelectionUserinfo), Context.Interaction.User.Id, uid);
|
_logger.LogInformation("{method}:{userId}:{uid}", nameof(SelectionUserinfo), Context.Interaction.User.Id, uid);
|
||||||
|
|
||||||
using var mareDb = GetDbContext();
|
using var mareDb = await GetDbContext().ConfigureAwait(false);
|
||||||
EmbedBuilder eb = new();
|
EmbedBuilder eb = new();
|
||||||
eb.WithTitle($"User Info for {uid}");
|
eb.WithTitle($"User Info for {uid}");
|
||||||
await HandleUserInfo(eb, mareDb, uid).ConfigureAwait(false);
|
await HandleUserInfo(eb, mareDb, uid).ConfigureAwait(false);
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ public partial class MareWizardModule
|
|||||||
AddHome(cb);
|
AddHome(cb);
|
||||||
if (userIsInVanityRole)
|
if (userIsInVanityRole)
|
||||||
{
|
{
|
||||||
using var db = GetDbContext();
|
using var db = await GetDbContext().ConfigureAwait(false);
|
||||||
await AddUserSelection(db, cb, "wizard-vanity-uid").ConfigureAwait(false);
|
await AddUserSelection(db, cb, "wizard-vanity-uid").ConfigureAwait(false);
|
||||||
await AddGroupSelection(db, cb, "wizard-vanity-gid").ConfigureAwait(false);
|
await AddGroupSelection(db, cb, "wizard-vanity-gid").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@@ -56,7 +56,7 @@ public partial class MareWizardModule
|
|||||||
|
|
||||||
_logger.LogInformation("{method}:{userId}:{uid}", nameof(SelectionVanityUid), Context.Interaction.User.Id, uid);
|
_logger.LogInformation("{method}:{userId}:{uid}", nameof(SelectionVanityUid), Context.Interaction.User.Id, uid);
|
||||||
|
|
||||||
using var db = GetDbContext();
|
using var db = await GetDbContext().ConfigureAwait(false);
|
||||||
var user = db.Users.Single(u => u.UID == uid);
|
var user = db.Users.Single(u => u.UID == uid);
|
||||||
EmbedBuilder eb = new();
|
EmbedBuilder eb = new();
|
||||||
eb.WithColor(Color.Purple);
|
eb.WithColor(Color.Purple);
|
||||||
@@ -90,7 +90,7 @@ public partial class MareWizardModule
|
|||||||
EmbedBuilder eb = new();
|
EmbedBuilder eb = new();
|
||||||
ComponentBuilder cb = new();
|
ComponentBuilder cb = new();
|
||||||
var desiredVanityUid = modal.DesiredVanityUID;
|
var desiredVanityUid = modal.DesiredVanityUID;
|
||||||
using var db = GetDbContext();
|
using var db = await GetDbContext().ConfigureAwait(false);
|
||||||
bool canAddVanityId = !db.Users.Any(u => u.UID == modal.DesiredVanityUID || u.Alias == modal.DesiredVanityUID);
|
bool canAddVanityId = !db.Users.Any(u => u.UID == modal.DesiredVanityUID || u.Alias == modal.DesiredVanityUID);
|
||||||
|
|
||||||
Regex rgx = new(@"^[_\-a-zA-Z0-9]{5,15}$", RegexOptions.ECMAScript);
|
Regex rgx = new(@"^[_\-a-zA-Z0-9]{5,15}$", RegexOptions.ECMAScript);
|
||||||
@@ -132,7 +132,7 @@ public partial class MareWizardModule
|
|||||||
{
|
{
|
||||||
_logger.LogInformation("{method}:{userId}:{uid}", nameof(SelectionVanityGid), Context.Interaction.User.Id, gid);
|
_logger.LogInformation("{method}:{userId}:{uid}", nameof(SelectionVanityGid), Context.Interaction.User.Id, gid);
|
||||||
|
|
||||||
using var db = GetDbContext();
|
using var db = await GetDbContext().ConfigureAwait(false);
|
||||||
var group = db.Groups.Single(u => u.GID == gid);
|
var group = db.Groups.Single(u => u.GID == gid);
|
||||||
EmbedBuilder eb = new();
|
EmbedBuilder eb = new();
|
||||||
eb.WithColor(Color.Purple);
|
eb.WithColor(Color.Purple);
|
||||||
@@ -166,7 +166,7 @@ public partial class MareWizardModule
|
|||||||
EmbedBuilder eb = new();
|
EmbedBuilder eb = new();
|
||||||
ComponentBuilder cb = new();
|
ComponentBuilder cb = new();
|
||||||
var desiredVanityGid = modal.DesiredVanityGID;
|
var desiredVanityGid = modal.DesiredVanityGID;
|
||||||
using var db = GetDbContext();
|
using var db = await GetDbContext().ConfigureAwait(false);
|
||||||
bool canAddVanityId = !db.Groups.Any(u => u.GID == modal.DesiredVanityGID || u.Alias == modal.DesiredVanityGID);
|
bool canAddVanityId = !db.Groups.Any(u => u.GID == modal.DesiredVanityGID || u.Alias == modal.DesiredVanityGID);
|
||||||
|
|
||||||
Regex rgx = new(@"^[_\-a-zA-Z0-9]{5,20}$", RegexOptions.ECMAScript);
|
Regex rgx = new(@"^[_\-a-zA-Z0-9]{5,20}$", RegexOptions.ECMAScript);
|
||||||
|
|||||||
@@ -15,24 +15,24 @@ namespace MareSynchronosServices.Discord;
|
|||||||
public partial class MareWizardModule : InteractionModuleBase
|
public partial class MareWizardModule : InteractionModuleBase
|
||||||
{
|
{
|
||||||
private ILogger<MareModule> _logger;
|
private ILogger<MareModule> _logger;
|
||||||
private IServiceProvider _services;
|
|
||||||
private DiscordBotServices _botServices;
|
private DiscordBotServices _botServices;
|
||||||
private IConfigurationService<ServerConfiguration> _mareClientConfigurationService;
|
private IConfigurationService<ServerConfiguration> _mareClientConfigurationService;
|
||||||
private IConfigurationService<ServicesConfiguration> _mareServicesConfiguration;
|
private IConfigurationService<ServicesConfiguration> _mareServicesConfiguration;
|
||||||
private IConnectionMultiplexer _connectionMultiplexer;
|
private IConnectionMultiplexer _connectionMultiplexer;
|
||||||
|
private readonly IDbContextFactory<MareDbContext> _dbContextFactory;
|
||||||
private Random random = new();
|
private Random random = new();
|
||||||
|
|
||||||
public MareWizardModule(ILogger<MareModule> logger, IServiceProvider services, DiscordBotServices botServices,
|
public MareWizardModule(ILogger<MareModule> logger, DiscordBotServices botServices,
|
||||||
IConfigurationService<ServerConfiguration> mareClientConfigurationService,
|
IConfigurationService<ServerConfiguration> mareClientConfigurationService,
|
||||||
IConfigurationService<ServicesConfiguration> mareServicesConfiguration,
|
IConfigurationService<ServicesConfiguration> mareServicesConfiguration,
|
||||||
IConnectionMultiplexer connectionMultiplexer)
|
IConnectionMultiplexer connectionMultiplexer, IDbContextFactory<MareDbContext> dbContextFactory)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_services = services;
|
|
||||||
_botServices = botServices;
|
_botServices = botServices;
|
||||||
_mareClientConfigurationService = mareClientConfigurationService;
|
_mareClientConfigurationService = mareClientConfigurationService;
|
||||||
_mareServicesConfiguration = mareServicesConfiguration;
|
_mareServicesConfiguration = mareServicesConfiguration;
|
||||||
_connectionMultiplexer = connectionMultiplexer;
|
_connectionMultiplexer = connectionMultiplexer;
|
||||||
|
_dbContextFactory = dbContextFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
[ComponentInteraction("wizard-captcha:*")]
|
[ComponentInteraction("wizard-captcha:*")]
|
||||||
@@ -115,7 +115,7 @@ public partial class MareWizardModule : InteractionModuleBase
|
|||||||
|
|
||||||
_logger.LogInformation("{method}:{userId}", nameof(StartWizard), Context.Interaction.User.Id);
|
_logger.LogInformation("{method}:{userId}", nameof(StartWizard), Context.Interaction.User.Id);
|
||||||
|
|
||||||
using var mareDb = GetDbContext();
|
using var mareDb = await GetDbContext().ConfigureAwait(false);
|
||||||
bool hasAccount = await mareDb.LodeStoneAuth.AnyAsync(u => u.DiscordId == Context.User.Id && u.StartedAt == null).ConfigureAwait(false);
|
bool hasAccount = await mareDb.LodeStoneAuth.AnyAsync(u => u.DiscordId == Context.User.Id && u.StartedAt == null).ConfigureAwait(false);
|
||||||
|
|
||||||
if (init)
|
if (init)
|
||||||
@@ -200,9 +200,9 @@ public partial class MareWizardModule : InteractionModuleBase
|
|||||||
public string Delete { get; set; }
|
public string Delete { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
private MareDbContext GetDbContext()
|
private async Task<MareDbContext> GetDbContext()
|
||||||
{
|
{
|
||||||
return _services.CreateScope().ServiceProvider.GetService<MareDbContext>();
|
return await _dbContextFactory.CreateDbContextAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<bool> ValidateInteraction()
|
private async Task<bool> ValidateInteraction()
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.SignalR;
|
|
||||||
|
|
||||||
// this is a very hacky way to attach this file server to the main mare hub signalr instance via redis
|
|
||||||
// signalr publishes the namespace and hubname into the redis backend so this needs to be equal to the original
|
|
||||||
// but I don't need to reimplement the hub completely as I only exclusively use it for internal connection calling
|
|
||||||
// from the queue service so I keep the namespace and name of the class the same so it can connect to the same channel
|
|
||||||
// if anyone finds a better way to do this let me know
|
|
||||||
|
|
||||||
#pragma warning disable IDE0130 // Namespace does not match folder structure
|
|
||||||
#pragma warning disable MA0048 // File name must match type name
|
|
||||||
namespace MareSynchronosServer.Hubs;
|
|
||||||
public class MareHub : Hub
|
|
||||||
{
|
|
||||||
public override Task OnConnectedAsync()
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Task OnDisconnectedAsync(Exception exception)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#pragma warning restore IDE0130 // Namespace does not match folder structure
|
|
||||||
#pragma warning restore MA0048 // File name must match type name
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using MareSynchronosServices;
|
using MareSynchronosServices;
|
||||||
using MareSynchronosShared.Data;
|
|
||||||
using MareSynchronosShared.Services;
|
using MareSynchronosShared.Services;
|
||||||
using MareSynchronosShared.Utils.Configuration;
|
using MareSynchronosShared.Utils.Configuration;
|
||||||
|
|
||||||
@@ -12,9 +11,6 @@ public class Program
|
|||||||
|
|
||||||
using (var scope = host.Services.CreateScope())
|
using (var scope = host.Services.CreateScope())
|
||||||
{
|
{
|
||||||
var services = scope.ServiceProvider;
|
|
||||||
using var dbContext = services.GetRequiredService<MareDbContext>();
|
|
||||||
|
|
||||||
var options = host.Services.GetService<IConfigurationService<ServicesConfiguration>>();
|
var options = host.Services.GetService<IConfigurationService<ServicesConfiguration>>();
|
||||||
var optionsServer = host.Services.GetService<IConfigurationService<ServerConfiguration>>();
|
var optionsServer = host.Services.GetService<IConfigurationService<ServerConfiguration>>();
|
||||||
var logger = host.Services.GetService<ILogger<Program>>();
|
var logger = host.Services.GetService<ILogger<Program>>();
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ using Prometheus;
|
|||||||
using MareSynchronosShared.Utils;
|
using MareSynchronosShared.Utils;
|
||||||
using MareSynchronosShared.Services;
|
using MareSynchronosShared.Services;
|
||||||
using StackExchange.Redis;
|
using StackExchange.Redis;
|
||||||
using MessagePack.Resolvers;
|
|
||||||
using MessagePack;
|
|
||||||
using MareSynchronosShared.Utils.Configuration;
|
using MareSynchronosShared.Utils.Configuration;
|
||||||
|
|
||||||
namespace MareSynchronosServices;
|
namespace MareSynchronosServices;
|
||||||
@@ -27,12 +25,6 @@ public class Startup
|
|||||||
|
|
||||||
var metricServer = new KestrelMetricServer(config.GetValueOrDefault<int>(nameof(MareConfigurationBase.MetricsPort), 4982));
|
var metricServer = new KestrelMetricServer(config.GetValueOrDefault<int>(nameof(MareConfigurationBase.MetricsPort), 4982));
|
||||||
metricServer.Start();
|
metricServer.Start();
|
||||||
|
|
||||||
app.UseRouting();
|
|
||||||
app.UseEndpoints(e =>
|
|
||||||
{
|
|
||||||
e.MapHub<MareSynchronosServer.Hubs.MareHub>("/dummyhub");
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ConfigureServices(IServiceCollection services)
|
public void ConfigureServices(IServiceCollection services)
|
||||||
@@ -47,6 +39,15 @@ public class Startup
|
|||||||
}).UseSnakeCaseNamingConvention();
|
}).UseSnakeCaseNamingConvention();
|
||||||
options.EnableThreadSafetyChecks(false);
|
options.EnableThreadSafetyChecks(false);
|
||||||
}, Configuration.GetValue(nameof(MareConfigurationBase.DbContextPoolSize), 1024));
|
}, Configuration.GetValue(nameof(MareConfigurationBase.DbContextPoolSize), 1024));
|
||||||
|
services.AddDbContextFactory<MareDbContext>(options =>
|
||||||
|
{
|
||||||
|
options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection"), builder =>
|
||||||
|
{
|
||||||
|
builder.MigrationsHistoryTable("_efmigrationshistory", "public");
|
||||||
|
builder.MigrationsAssembly("MareSynchronosShared");
|
||||||
|
}).UseSnakeCaseNamingConvention();
|
||||||
|
options.EnableThreadSafetyChecks(false);
|
||||||
|
});
|
||||||
|
|
||||||
services.AddSingleton(m => new MareMetrics(m.GetService<ILogger<MareMetrics>>(), new List<string> { },
|
services.AddSingleton(m => new MareMetrics(m.GetService<ILogger<MareMetrics>>(), new List<string> { },
|
||||||
new List<string> { }));
|
new List<string> { }));
|
||||||
@@ -58,35 +59,6 @@ public class Startup
|
|||||||
ConnectionMultiplexer connectionMultiplexer = ConnectionMultiplexer.Connect(options);
|
ConnectionMultiplexer connectionMultiplexer = ConnectionMultiplexer.Connect(options);
|
||||||
services.AddSingleton<IConnectionMultiplexer>(connectionMultiplexer);
|
services.AddSingleton<IConnectionMultiplexer>(connectionMultiplexer);
|
||||||
|
|
||||||
var signalRServiceBuilder = services.AddSignalR(hubOptions =>
|
|
||||||
{
|
|
||||||
hubOptions.MaximumReceiveMessageSize = long.MaxValue;
|
|
||||||
hubOptions.EnableDetailedErrors = true;
|
|
||||||
hubOptions.MaximumParallelInvocationsPerClient = 10;
|
|
||||||
hubOptions.StreamBufferCapacity = 200;
|
|
||||||
}).AddMessagePackProtocol(opt =>
|
|
||||||
{
|
|
||||||
var resolver = CompositeResolver.Create(StandardResolverAllowPrivate.Instance,
|
|
||||||
BuiltinResolver.Instance,
|
|
||||||
AttributeFormatterResolver.Instance,
|
|
||||||
// replace enum resolver
|
|
||||||
DynamicEnumAsStringResolver.Instance,
|
|
||||||
DynamicGenericResolver.Instance,
|
|
||||||
DynamicUnionResolver.Instance,
|
|
||||||
DynamicObjectResolver.Instance,
|
|
||||||
PrimitiveObjectResolver.Instance,
|
|
||||||
// final fallback(last priority)
|
|
||||||
StandardResolver.Instance);
|
|
||||||
|
|
||||||
opt.SerializerOptions = MessagePackSerializerOptions.Standard
|
|
||||||
.WithCompression(MessagePackCompression.Lz4Block)
|
|
||||||
.WithResolver(resolver);
|
|
||||||
});
|
|
||||||
|
|
||||||
// configure redis for SignalR
|
|
||||||
var redisConnection = mareConfig.GetValue(nameof(MareConfigurationBase.RedisConnectionString), string.Empty);
|
|
||||||
signalRServiceBuilder.AddStackExchangeRedis(redisConnection, options => { });
|
|
||||||
|
|
||||||
services.Configure<ServicesConfiguration>(Configuration.GetRequiredSection("MareSynchronos"));
|
services.Configure<ServicesConfiguration>(Configuration.GetRequiredSection("MareSynchronos"));
|
||||||
services.Configure<ServerConfiguration>(Configuration.GetRequiredSection("MareSynchronos"));
|
services.Configure<ServerConfiguration>(Configuration.GetRequiredSection("MareSynchronos"));
|
||||||
services.Configure<MareConfigurationBase>(Configuration.GetRequiredSection("MareSynchronos"));
|
services.Configure<MareConfigurationBase>(Configuration.GetRequiredSection("MareSynchronos"));
|
||||||
|
|||||||
Reference in New Issue
Block a user