add secondary UID stuff

This commit is contained in:
rootdarkarchon
2023-01-31 23:33:04 +01:00
parent 96e89437c0
commit 677224e363
10 changed files with 1196 additions and 177 deletions

View File

@@ -3,6 +3,10 @@ using Microsoft.EntityFrameworkCore;
using MareSynchronosServer.Utils;
using MareSynchronosShared.Utils;
using Microsoft.IdentityModel.Tokens;
using MareSynchronos.API.Data;
using MareSynchronos.API.Dto.Group;
using MareSynchronosShared.Metrics;
using Microsoft.AspNetCore.SignalR;
namespace MareSynchronosServer.Hubs;
@@ -161,4 +165,111 @@ public partial class MareHub
return (string.Equals(group.OwnerUID, UserUID, StringComparison.Ordinal), group);
}
private async Task DeleteUser(User user)
{
var ownPairData = await _dbContext.ClientPairs.Where(u => u.User.UID == user.UID).ToListAsync().ConfigureAwait(false);
var auth = await _dbContext.Auth.SingleAsync(u => u.UserUID == user.UID).ConfigureAwait(false);
var lodestone = await _dbContext.LodeStoneAuth.SingleOrDefaultAsync(a => a.User.UID == user.UID).ConfigureAwait(false);
var groupPairs = await _dbContext.GroupPairs.Where(g => g.GroupUserUID == user.UID).ToListAsync().ConfigureAwait(false);
if (lodestone != null)
{
_dbContext.Remove(lodestone);
}
while (_dbContext.Files.Any(f => f.Uploader == user))
{
await Task.Delay(1000).ConfigureAwait(false);
}
_dbContext.ClientPairs.RemoveRange(ownPairData);
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
var otherPairData = await _dbContext.ClientPairs.Include(u => u.User)
.Where(u => u.OtherUser.UID == user.UID).AsNoTracking().ToListAsync().ConfigureAwait(false);
foreach (var pair in otherPairData)
{
await Clients.User(pair.UserUID).Client_UserRemoveClientPair(new(user.ToUserData())).ConfigureAwait(false);
}
foreach (var pair in groupPairs)
{
await UserLeaveGroup(new GroupDto(new GroupData(pair.GroupGID)), user.UID).ConfigureAwait(false);
}
_mareMetrics.IncCounter(MetricsAPI.CounterUsersRegisteredDeleted, 1);
_dbContext.ClientPairs.RemoveRange(otherPairData);
_dbContext.Users.Remove(user);
_dbContext.Auth.Remove(auth);
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
}
private async Task UserLeaveGroup(GroupDto dto, string userUid)
{
_logger.LogCallInfo(MareHubLogger.Args(dto));
var (exists, groupPair) = await TryValidateUserInGroup(dto.Group.GID, userUid).ConfigureAwait(false);
if (!exists) return;
var group = await _dbContext.Groups.SingleOrDefaultAsync(g => g.GID == dto.Group.GID).ConfigureAwait(false);
var groupPairs = await _dbContext.GroupPairs.Where(p => p.GroupGID == group.GID).ToListAsync().ConfigureAwait(false);
var groupPairsWithoutSelf = groupPairs.Where(p => !string.Equals(p.GroupUserUID, userUid, StringComparison.Ordinal)).ToList();
_dbContext.GroupPairs.Remove(groupPair);
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
await Clients.User(userUid).Client_GroupDelete(new GroupDto(group.ToGroupData())).ConfigureAwait(false);
bool ownerHasLeft = string.Equals(group.OwnerUID, userUid, StringComparison.Ordinal);
if (ownerHasLeft)
{
if (!groupPairsWithoutSelf.Any())
{
_logger.LogCallInfo(MareHubLogger.Args(dto, "Deleted"));
_dbContext.Groups.Remove(group);
}
else
{
var groupHasMigrated = await SharedDbFunctions.MigrateOrDeleteGroup(_dbContext, group, groupPairsWithoutSelf, _maxExistingGroupsByUser).ConfigureAwait(false);
if (groupHasMigrated.Item1)
{
_logger.LogCallInfo(MareHubLogger.Args(dto, "Migrated", groupHasMigrated.Item2));
var user = await _dbContext.Users.SingleAsync(u => u.UID == groupHasMigrated.Item2).ConfigureAwait(false);
await Clients.Users(groupPairsWithoutSelf.Select(p => p.GroupUserUID)).Client_GroupSendInfo(new GroupInfoDto(group.ToGroupData(),
user.ToUserData(), group.GetGroupPermissions())).ConfigureAwait(false);
}
else
{
_logger.LogCallInfo(MareHubLogger.Args(dto, "Deleted"));
await Clients.Users(groupPairsWithoutSelf.Select(p => p.GroupUserUID)).Client_GroupDelete(dto).ConfigureAwait(false);
await SendGroupDeletedToAll(groupPairs).ConfigureAwait(false);
return;
}
}
}
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
_logger.LogCallInfo(MareHubLogger.Args(dto, "Success"));
await Clients.Users(groupPairsWithoutSelf.Select(p => p.GroupUserUID)).Client_GroupPairLeft(new GroupPairDto(dto.Group, groupPair.GroupUser.ToUserData())).ConfigureAwait(false);
var allUserPairs = await GetAllPairedClientsWithPauseState().ConfigureAwait(false);
var ident = await GetUserIdent(userUid).ConfigureAwait(false);
foreach (var groupUserPair in groupPairsWithoutSelf)
{
await UserGroupLeave(groupUserPair, allUserPairs, ident, userUid).ConfigureAwait(false);
}
}
}

View File

@@ -298,68 +298,7 @@ public partial class MareHub
[Authorize(Policy = "Identified")]
public async Task GroupLeave(GroupDto dto)
{
_logger.LogCallInfo(MareHubLogger.Args(dto));
var (exists, groupPair) = await TryValidateUserInGroup(dto.Group.GID).ConfigureAwait(false);
if (!exists) return;
var group = await _dbContext.Groups.SingleOrDefaultAsync(g => g.GID == dto.Group.GID).ConfigureAwait(false);
var groupPairs = await _dbContext.GroupPairs.Where(p => p.GroupGID == group.GID).ToListAsync().ConfigureAwait(false);
var groupPairsWithoutSelf = groupPairs.Where(p => !string.Equals(p.GroupUserUID, UserUID, StringComparison.Ordinal)).ToList();
_dbContext.GroupPairs.Remove(groupPair);
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
await Clients.User(UserUID).Client_GroupDelete(new GroupDto(group.ToGroupData())).ConfigureAwait(false);
bool ownerHasLeft = string.Equals(group.OwnerUID, UserUID, StringComparison.Ordinal);
if (ownerHasLeft)
{
if (!groupPairsWithoutSelf.Any())
{
_logger.LogCallInfo(MareHubLogger.Args(dto, "Deleted"));
_dbContext.Groups.Remove(group);
}
else
{
var groupHasMigrated = await SharedDbFunctions.MigrateOrDeleteGroup(_dbContext, group, groupPairsWithoutSelf, _maxExistingGroupsByUser).ConfigureAwait(false);
if (groupHasMigrated.Item1)
{
_logger.LogCallInfo(MareHubLogger.Args(dto, "Migrated", groupHasMigrated.Item2));
var user = await _dbContext.Users.SingleAsync(u => u.UID == groupHasMigrated.Item2).ConfigureAwait(false);
await Clients.Users(groupPairsWithoutSelf.Select(p => p.GroupUserUID)).Client_GroupSendInfo(new GroupInfoDto(group.ToGroupData(),
user.ToUserData(), group.GetGroupPermissions())).ConfigureAwait(false);
}
else
{
_logger.LogCallInfo(MareHubLogger.Args(dto, "Deleted"));
await Clients.Users(groupPairsWithoutSelf.Select(p => p.GroupUserUID)).Client_GroupDelete(dto).ConfigureAwait(false);
await SendGroupDeletedToAll(groupPairs).ConfigureAwait(false);
return;
}
}
}
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
_logger.LogCallInfo(MareHubLogger.Args(dto, "Success"));
await Clients.Users(groupPairsWithoutSelf.Select(p => p.GroupUserUID)).Client_GroupPairLeft(new GroupPairDto(dto.Group, groupPair.GroupUser.ToUserData())).ConfigureAwait(false);
var allUserPairs = await GetAllPairedClientsWithPauseState().ConfigureAwait(false);
foreach (var groupUserPair in groupPairsWithoutSelf)
{
await UserGroupLeave(groupUserPair, allUserPairs, UserCharaIdent).ConfigureAwait(false);
}
await UserLeaveGroup(dto, UserUID).ConfigureAwait(false);
}
[Authorize(Policy = "Identified")]

View File

@@ -21,41 +21,13 @@ public partial class MareHub
_logger.LogCallInfo();
var userEntry = await _dbContext.Users.SingleAsync(u => u.UID == UserUID).ConfigureAwait(false);
var ownPairData = await _dbContext.ClientPairs.Where(u => u.User.UID == UserUID).ToListAsync().ConfigureAwait(false);
var auth = await _dbContext.Auth.SingleAsync(u => u.UserUID == UserUID).ConfigureAwait(false);
var lodestone = await _dbContext.LodeStoneAuth.SingleOrDefaultAsync(a => a.User.UID == UserUID).ConfigureAwait(false);
var groupPairs = await _dbContext.GroupPairs.Where(g => g.GroupUserUID == UserUID).ToListAsync().ConfigureAwait(false);
if (lodestone != null)
var secondaryUsers = await _dbContext.Auth.Include(u => u.User).Where(u => u.PrimaryUserUID == UserUID).Select(c => c.User).ToListAsync().ConfigureAwait(false);
foreach (var user in secondaryUsers)
{
_dbContext.Remove(lodestone);
await DeleteUser(user).ConfigureAwait(false);
}
while (_dbContext.Files.Any(f => f.Uploader == userEntry))
{
await Task.Delay(1000).ConfigureAwait(false);
}
_dbContext.ClientPairs.RemoveRange(ownPairData);
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
var otherPairData = await _dbContext.ClientPairs.Include(u => u.User)
.Where(u => u.OtherUser.UID == UserUID).AsNoTracking().ToListAsync().ConfigureAwait(false);
foreach (var pair in otherPairData)
{
await Clients.User(pair.UserUID).Client_UserRemoveClientPair(new(userEntry.ToUserData())).ConfigureAwait(false);
}
foreach (var pair in groupPairs)
{
await GroupLeave(new GroupDto(new GroupData(pair.GroupGID))).ConfigureAwait(false);
}
_mareMetrics.IncCounter(MetricsAPI.CounterUsersRegisteredDeleted, 1);
_dbContext.ClientPairs.RemoveRange(otherPairData);
_dbContext.Users.Remove(userEntry);
_dbContext.Auth.Remove(auth);
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
await DeleteUser(userEntry).ConfigureAwait(false);
}
[Authorize(Policy = "Identified")]

View File

@@ -119,7 +119,15 @@ internal class DiscordBot : IHostedService
if (discordUser == null || !discordUser.RoleIds.Any(u => allowedRoleIds.Contains(u)))
{
_logger.LogInformation($"User {lodestoneAuth.User.UID} not in allowed roles, deleting alias");
lodestoneAuth.User.Alias = string.Empty;
lodestoneAuth.User.Alias = null;
var secondaryUsers = await db.Auth.Include(u => u.User).Where(u => u.PrimaryUserUID == lodestoneAuth.User.UID).ToListAsync().ConfigureAwait(false);
foreach (var secondaryUser in secondaryUsers)
{
_logger.LogInformation($"Secondary User {secondaryUser.User.UID} not in allowed roles, deleting alias");
secondaryUser.User.Alias = null;
db.Update(secondaryUser.User);
}
db.Update(lodestoneAuth.User);
}

View File

@@ -52,7 +52,7 @@ public class MareModule : InteractionModuleBase
Context.Interaction.User.Id, nameof(Register),
string.Join(",", new[] { $"{nameof(overwrite)}:{overwrite}" }));
await TryRespondAsync(async () =>
try
{
if (overwrite)
{
@@ -60,24 +60,59 @@ public class MareModule : InteractionModuleBase
}
await RespondWithModalAsync<LodestoneModal>("register_modal").ConfigureAwait(false);
});
}
catch (Exception ex)
{
EmbedBuilder eb = new();
eb.WithTitle("An error occured");
eb.WithDescription("Please report this error to bug-reports: " + Environment.NewLine + ex.Message + Environment.NewLine + ex.StackTrace + Environment.NewLine);
await RespondAsync(embeds: new Embed[] { eb.Build() }, ephemeral: true).ConfigureAwait(false);
}
}
[SlashCommand("createsecondaryuid", "Creates a new Secret Key to be used for alts")]
public async Task AddSecondary()
{
try
{
var embed = await HandleAddSecondary(Context.User.Id).ConfigureAwait(false);
await RespondAsync(embeds: new[] { embed }, ephemeral: true).ConfigureAwait(false);
}
catch (Exception ex)
{
EmbedBuilder eb = new();
eb.WithTitle("An error occured");
eb.WithDescription("Please report this error to bug-reports: " + Environment.NewLine + ex.Message + Environment.NewLine + ex.StackTrace + Environment.NewLine);
await RespondAsync(embeds: new Embed[] { eb.Build() }, ephemeral: true).ConfigureAwait(false);
}
}
[SlashCommand("setvanityuid", "Sets your Vanity UID.")]
public async Task SetVanityUid([Summary("vanity_uid", "Desired Vanity UID")] string vanityUid)
public async Task SetVanityUid([Summary("vanity_uid", "Desired Vanity UID")] string vanityUid,
[Summary("secondary_uid", "Will set the vanity UID for a secondary UID")] string? secondaryUid = null)
{
_logger.LogInformation("SlashCommand:{userId}:{Method}:{params}",
Context.Interaction.User.Id, nameof(SetVanityUid),
string.Join(",", new[] { $"{nameof(vanityUid)}:{vanityUid}" }));
await TryRespondAsync(async () =>
try
{
EmbedBuilder eb = new();
eb = await HandleVanityUid(eb, Context.User.Id, vanityUid);
eb = await HandleVanityUid(eb, Context.User.Id, vanityUid, secondaryUid);
await RespondAsync(embeds: new[] { eb.Build() }, ephemeral: true).ConfigureAwait(false);
});
}
catch (Exception ex)
{
EmbedBuilder eb = new();
eb.WithTitle("An error occured");
eb.WithDescription("Please report this error to bug-reports: " + Environment.NewLine + ex.Message + Environment.NewLine + ex.StackTrace + Environment.NewLine);
await RespondAsync(embeds: new Embed[] { eb.Build() }, ephemeral: true).ConfigureAwait(false);
}
}
[SlashCommand("setsyncshellvanityid", "Sets a Vanity GID for a Syncshell")]
@@ -89,14 +124,22 @@ public class MareModule : InteractionModuleBase
Context.Interaction.User.Id, nameof(SetSyncshellVanityId),
string.Join(",", new[] { $"{nameof(syncshellId)}:{syncshellId}", $"{nameof(vanityId)}:{vanityId}" }));
await TryRespondAsync(async () =>
try
{
EmbedBuilder eb = new();
eb = await HandleVanityGid(eb, Context.User.Id, syncshellId, vanityId);
await RespondAsync(embeds: new[] { eb.Build() }, ephemeral: true).ConfigureAwait(false);
});
}
catch (Exception ex)
{
EmbedBuilder eb = new();
eb.WithTitle("An error occured");
eb.WithDescription("Please report this error to bug-reports: " + Environment.NewLine + ex.Message + Environment.NewLine + ex.StackTrace + Environment.NewLine);
await RespondAsync(embeds: new Embed[] { eb.Build() }, ephemeral: true).ConfigureAwait(false);
}
}
[SlashCommand("verify", "Finishes the registration process for the Mare Synchronos server of this Discord")]
@@ -104,7 +147,7 @@ public class MareModule : InteractionModuleBase
{
_logger.LogInformation("SlashCommand:{userId}:{Method}",
Context.Interaction.User.Id, nameof(Verify));
await TryRespondAsync(async () =>
try
{
EmbedBuilder eb = new();
if (_botServices.VerificationQueue.Any(u => u.Key == Context.User.Id))
@@ -116,7 +159,7 @@ public class MareModule : InteractionModuleBase
else if (!_botServices.DiscordLodestoneMapping.ContainsKey(Context.User.Id))
{
eb.WithTitle("Cannot verify registration");
eb.WithDescription("You need to **/register** first before you can **/verify**");
eb.WithDescription("You need to **/register** first before you can **/verify**" + Environment.NewLine + "If your registration got stuck for some reason, use **/register overwrite:true**");
await RespondAsync(embeds: new[] { eb.Build() }, ephemeral: true).ConfigureAwait(false);
}
else
@@ -124,7 +167,15 @@ public class MareModule : InteractionModuleBase
await DeferAsync(ephemeral: true).ConfigureAwait(false);
_botServices.VerificationQueue.Enqueue(new KeyValuePair<ulong, Action<IServiceProvider>>(Context.User.Id, async (sp) => await HandleVerifyAsync((SocketSlashCommand)Context.Interaction, sp)));
}
});
}
catch (Exception ex)
{
EmbedBuilder eb = new();
eb.WithTitle("An error occured");
eb.WithDescription("Please report this error to bug-reports: " + Environment.NewLine + ex.Message + Environment.NewLine + ex.StackTrace + Environment.NewLine);
await RespondAsync(embeds: new Embed[] { eb.Build() }, ephemeral: true).ConfigureAwait(false);
}
}
[SlashCommand("verify_relink", "Finishes the relink process for your user on the Mare Synchronos server of this Discord")]
@@ -132,7 +183,8 @@ public class MareModule : InteractionModuleBase
{
_logger.LogInformation("SlashCommand:{userId}:{Method}",
Context.Interaction.User.Id, nameof(VerifyRelink));
await TryRespondAsync(async () =>
try
{
EmbedBuilder eb = new();
if (_botServices.VerificationQueue.Any(u => u.Key == Context.User.Id))
@@ -152,33 +204,51 @@ public class MareModule : InteractionModuleBase
await DeferAsync(ephemeral: true).ConfigureAwait(false);
_botServices.VerificationQueue.Enqueue(new KeyValuePair<ulong, Action<IServiceProvider>>(Context.User.Id, async (sp) => await HandleVerifyRelinkAsync((SocketSlashCommand)Context.Interaction, sp)));
}
});
}
catch (Exception ex)
{
EmbedBuilder eb = new();
eb.WithTitle("An error occured");
eb.WithDescription("Please report this error to bug-reports: " + Environment.NewLine + ex.Message + Environment.NewLine + ex.StackTrace + Environment.NewLine);
await RespondAsync(embeds: new Embed[] { eb.Build() }, ephemeral: true).ConfigureAwait(false);
}
}
[SlashCommand("recover", "Allows you to recover your account by generating a new secret key")]
public async Task Recover()
public async Task Recover([Summary("secondary_uid", "(Optional) Your secondary UID")] string? secondaryUid = null)
{
_logger.LogInformation("SlashCommand:{userId}:{Method}",
Context.Interaction.User.Id, nameof(Recover));
await RespondWithModalAsync<LodestoneModal>("recover_modal").ConfigureAwait(false);
await RespondWithModalAsync<LodestoneModal>($"recover_modal,{secondaryUid}").ConfigureAwait(false);
}
[SlashCommand("userinfo", "Shows you your user information")]
public async Task UserInfo(
public async Task UserInfo([Summary("secondary_uid", "(Optional) Your secondary UID")] string? secondaryUid = null,
[Summary("discord_user", "ADMIN ONLY: Discord User to check for")] IUser? discordUser = null,
[Summary("uid", "ADMIN ONLY: UID to check for")] string? uid = null)
{
_logger.LogInformation("SlashCommand:{userId}:{Method}",
Context.Interaction.User.Id, nameof(UserInfo));
await TryRespondAsync(async () =>
try
{
EmbedBuilder eb = new();
eb = await HandleUserInfo(eb, Context.User.Id, discordUser?.Id ?? null, uid);
eb = await HandleUserInfo(eb, Context.User.Id, secondaryUid, discordUser?.Id ?? null, uid);
await RespondAsync(embeds: new[] { eb.Build() }, ephemeral: true).ConfigureAwait(false);
});
}
catch (Exception ex)
{
EmbedBuilder eb = new();
eb.WithTitle("An error occured");
eb.WithDescription("Please report this error to bug-reports: " + Environment.NewLine + ex.Message + Environment.NewLine + ex.StackTrace + Environment.NewLine);
await RespondAsync(embeds: new Embed[] { eb.Build() }, ephemeral: true).ConfigureAwait(false);
}
}
[SlashCommand("relink", "Allows you to link a new Discord account to an existing Mare account")]
@@ -196,12 +266,20 @@ public class MareModule : InteractionModuleBase
Context.Interaction.User.Id, nameof(UserAdd),
string.Join(",", new[] { $"{nameof(desiredUid)}:{desiredUid}" }));
await TryRespondAsync(async () =>
try
{
var embed = await HandleUserAdd(desiredUid, Context.User.Id);
await RespondAsync(embeds: new[] { embed }, ephemeral: true).ConfigureAwait(false);
});
}
catch (Exception ex)
{
EmbedBuilder eb = new();
eb.WithTitle("An error occured");
eb.WithDescription("Please report this error to bug-reports: " + Environment.NewLine + ex.Message + Environment.NewLine + ex.StackTrace + Environment.NewLine);
await RespondAsync(embeds: new Embed[] { eb.Build() }, ephemeral: true).ConfigureAwait(false);
}
}
[SlashCommand("message", "ADMIN ONLY: sends a message to clients")]
@@ -244,17 +322,25 @@ public class MareModule : InteractionModuleBase
}
}
[ModalInteraction("recover_modal")]
public async Task RecoverModal(LodestoneModal modal)
[ModalInteraction("recover_modal,*")]
public async Task RecoverModal(string? secondaryUid, LodestoneModal modal)
{
_logger.LogInformation("Modal:{userId}:{Method}",
Context.Interaction.User.Id, nameof(RecoverModal));
await TryRespondAsync(async () =>
try
{
var embed = await HandleRecoverModalAsync(modal, Context.User.Id).ConfigureAwait(false);
var embed = await HandleRecoverModalAsync(modal, Context.User.Id, secondaryUid).ConfigureAwait(false);
await RespondAsync(embeds: new Embed[] { embed }, ephemeral: true).ConfigureAwait(false);
});
}
catch (Exception ex)
{
EmbedBuilder eb = new();
eb.WithTitle("An error occured");
eb.WithDescription("Please report this error to bug-reports: " + Environment.NewLine + ex.Message + Environment.NewLine + ex.StackTrace + Environment.NewLine);
await RespondAsync(embeds: new Embed[] { eb.Build() }, ephemeral: true).ConfigureAwait(false);
}
}
[ModalInteraction("register_modal")]
@@ -263,11 +349,19 @@ public class MareModule : InteractionModuleBase
_logger.LogInformation("Modal:{userId}:{Method}",
Context.Interaction.User.Id, nameof(RegisterModal));
await TryRespondAsync(async () =>
try
{
var embed = await HandleRegisterModalAsync(modal, Context.User.Id).ConfigureAwait(false);
await RespondAsync(embeds: new Embed[] { embed }, ephemeral: true).ConfigureAwait(false);
});
}
catch (Exception ex)
{
EmbedBuilder eb = new();
eb.WithTitle("An error occured");
eb.WithDescription("Please report this error to bug-reports: " + Environment.NewLine + ex.Message + Environment.NewLine + ex.StackTrace + Environment.NewLine);
await RespondAsync(embeds: new Embed[] { eb.Build() }, ephemeral: true).ConfigureAwait(false);
}
}
[ModalInteraction("relink_modal")]
@@ -276,11 +370,79 @@ public class MareModule : InteractionModuleBase
_logger.LogInformation("Modal:{userId}:{Method}",
Context.Interaction.User.Id, nameof(RelinkModal));
await TryRespondAsync(async () =>
try
{
var embed = await HandleRelinkModalAsync(modal, Context.User.Id).ConfigureAwait(false);
await RespondAsync(embeds: new Embed[] { embed }, ephemeral: true).ConfigureAwait(false);
});
}
catch (Exception ex)
{
EmbedBuilder eb = new();
eb.WithTitle("An error occured");
eb.WithDescription("Please report this error to bug-reports: " + Environment.NewLine + ex.Message + Environment.NewLine + ex.StackTrace + Environment.NewLine);
await RespondAsync(embeds: new Embed[] { eb.Build() }, ephemeral: true).ConfigureAwait(false);
}
}
public async Task<Embed> HandleAddSecondary(ulong discordUserId)
{
var embed = new EmbedBuilder();
using var scope = _services.CreateScope();
using var db = scope.ServiceProvider.GetService<MareDbContext>();
var lodestoneAuth = await db.LodeStoneAuth.Include(u => u.User).SingleOrDefaultAsync(a => a.DiscordId == discordUserId).ConfigureAwait(false);
if (lodestoneAuth == null)
{
embed.WithTitle("Failed to add secondary user");
embed.WithDescription("You have no registered Mare account yet. Register a Mare account first before trying to add secondary keys.");
return embed.Build();
}
var secondaryCount = await db.Auth.CountAsync(u => u.PrimaryUserUID == lodestoneAuth.User.UID).ConfigureAwait(false);
if (await db.Auth.CountAsync(u => u.PrimaryUserUID == lodestoneAuth.User.UID).ConfigureAwait(false) >= 25)
{
embed.WithTitle("Failed to add secondary user");
embed.WithDescription("You already made 25 secondary UIDs, which is the limit.");
return embed.Build();
}
User newUser = new()
{
IsAdmin = false,
IsModerator = false,
LastLoggedIn = DateTime.UtcNow,
};
var hasValidUid = false;
while (!hasValidUid)
{
var uid = StringUtils.GenerateRandomString(10);
if (await db.Users.AnyAsync(u => u.UID == uid || u.Alias == uid).ConfigureAwait(false)) continue;
newUser.UID = uid;
hasValidUid = true;
}
var computedHash = StringUtils.Sha256String(StringUtils.GenerateRandomString(64) + DateTime.UtcNow.ToString());
var auth = new Auth()
{
HashedKey = StringUtils.Sha256String(computedHash),
User = newUser,
PrimaryUser = lodestoneAuth.User
};
await db.Users.AddAsync(newUser).ConfigureAwait(false);
await db.Auth.AddAsync(auth).ConfigureAwait(false); ;
await db.SaveChangesAsync().ConfigureAwait(false);
embed.WithTitle("Secondary UID created");
embed.AddField("UID", newUser.UID);
embed.AddField("Secret Key", computedHash);
embed.AddField("Secondary UIDs", $"You now have {secondaryCount + 1}/25 secondary UIDs");
return embed.Build();
}
public async Task<Embed> HandleUserAdd(string desiredUid, ulong discordUserId)
@@ -328,38 +490,24 @@ public class MareModule : InteractionModuleBase
return embed.Build();
}
private async Task TryRespondAsync(Action act)
{
try
{
act();
}
catch (Exception ex)
{
EmbedBuilder eb = new();
eb.WithTitle("An error occured");
eb.WithDescription("Please report this error to bug-reports: " + Environment.NewLine + ex.Message + Environment.NewLine + ex.StackTrace + Environment.NewLine);
await RespondAsync(embeds: new Embed[] { eb.Build() }, ephemeral: true).ConfigureAwait(false);
}
}
private async Task<EmbedBuilder> HandleUserInfo(EmbedBuilder eb, ulong id, ulong? optionalUser = null, string? uid = null)
private async Task<EmbedBuilder> HandleUserInfo(EmbedBuilder eb, ulong id, string? secondaryUserUid = null, ulong? optionalUser = null, string? uid = null)
{
bool showForSecondaryUser = secondaryUserUid != null;
using var scope = _services.CreateScope();
await using var db = scope.ServiceProvider.GetRequiredService<MareDbContext>();
var self = await db.LodeStoneAuth.Include(u => u.User).SingleOrDefaultAsync(u => u.DiscordId == id).ConfigureAwait(false);
var primaryUser = await db.LodeStoneAuth.Include(u => u.User).SingleOrDefaultAsync(u => u.DiscordId == id).ConfigureAwait(false);
ulong userToCheckForDiscordId = id;
if (self == null)
if (primaryUser == null)
{
eb.WithTitle("No account");
eb.WithDescription("No Mare account was found associated to your Discord user");
return eb;
}
bool isAdminCall = self.User.IsModerator || self.User.IsAdmin;
bool isAdminCall = primaryUser.User.IsModerator || primaryUser.User.IsAdmin;
if ((optionalUser != null || uid != null) && !isAdminCall)
{
@@ -391,21 +539,44 @@ public class MareModule : InteractionModuleBase
var lodestoneUser = await db.LodeStoneAuth.Include(u => u.User).SingleOrDefaultAsync(u => u.DiscordId == userToCheckForDiscordId).ConfigureAwait(false);
var dbUser = lodestoneUser.User;
var auth = await db.Auth.SingleOrDefaultAsync(u => u.UserUID == dbUser.UID).ConfigureAwait(false);
var identity = await _connectionMultiplexer.GetDatabase().StringGetAsync("UID:" + dbUser.UID).ConfigureAwait(false);
if (showForSecondaryUser)
{
dbUser = (await db.Auth.Include(u => u.User).SingleOrDefaultAsync(u => u.PrimaryUserUID == dbUser.UID && u.UserUID == secondaryUserUid))?.User;
if (dbUser == null)
{
eb.WithTitle("No such secondary UID");
eb.WithDescription($"A secondary UID {secondaryUserUid} was not found attached to your primary UID {primaryUser.User.UID}.");
return eb;
}
}
var auth = await db.Auth.Include(u => u.PrimaryUser).SingleOrDefaultAsync(u => u.UserUID == dbUser.UID).ConfigureAwait(false);
var groups = await db.Groups.Where(g => g.OwnerUID == dbUser.UID).ToListAsync().ConfigureAwait(false);
var groupsJoined = await db.GroupPairs.Where(g => g.GroupUserUID == dbUser.UID).ToListAsync().ConfigureAwait(false);
var identity = await _connectionMultiplexer.GetDatabase().StringGetAsync("UID:" + dbUser.UID).ConfigureAwait(false);
eb.WithTitle("User Information");
eb.WithDescription("This is the user information for Discord User Id " + userToCheckForDiscordId + Environment.NewLine
+ "If you want to verify your secret key is valid, go to https://emn178.github.io/online-tools/sha256.html and copy your secret key into there and compare it to the Hashed Secret Key.");
eb.WithDescription("This is the user information for Discord User <@" + userToCheckForDiscordId + ">" + Environment.NewLine + Environment.NewLine
+ "If you want to verify your secret key is valid, go to https://emn178.github.io/online-tools/sha256.html and copy your secret key into there and compare it to the Hashed Secret Key provided below.");
eb.AddField("UID", dbUser.UID);
if (!string.IsNullOrEmpty(dbUser.Alias))
{
eb.AddField("Vanity UID", dbUser.Alias);
}
if (showForSecondaryUser)
{
eb.AddField("Primary UID for " + dbUser.UID, auth.PrimaryUserUID);
}
else
{
var secondaryUIDs = await db.Auth.Where(p => p.PrimaryUserUID == dbUser.UID).Select(p => p.UserUID).ToListAsync();
if (secondaryUIDs.Any())
{
eb.AddField("Secondary UIDs", string.Join(Environment.NewLine, secondaryUIDs));
}
}
eb.AddField("Last Online (UTC)", dbUser.LastLoggedIn.ToString("U"));
eb.AddField("Currently online: ", !string.IsNullOrEmpty(identity));
eb.AddField("Currently online ", !string.IsNullOrEmpty(identity));
eb.AddField("Hashed Secret Key", auth.HashedKey);
eb.AddField("Joined Syncshells", groupsJoined.Count);
eb.AddField("Owned Syncshells", groups.Count);
@@ -427,7 +598,7 @@ public class MareModule : InteractionModuleBase
return eb;
}
private async Task<Embed> HandleRecoverModalAsync(LodestoneModal arg, ulong userid)
private async Task<Embed> HandleRecoverModalAsync(LodestoneModal arg, ulong userid, string? secondaryUid)
{
var embed = new EmbedBuilder();
@@ -449,7 +620,6 @@ public class MareModule : InteractionModuleBase
.FirstOrDefaultAsync(a => a.DiscordId == userid && a.HashedLodestoneId == hashedLodestoneId)
.ConfigureAwait(false);
// check if discord id or lodestone id is banned
if (existingLodestoneAuth == null || existingLodestoneAuth.User == null)
{
embed.WithTitle("Recovery failed");
@@ -457,18 +627,46 @@ public class MareModule : InteractionModuleBase
}
else
{
var previousAuth = await db.Auth.FirstOrDefaultAsync(u => u.UserUID == existingLodestoneAuth.User.UID);
if (previousAuth != null)
string computedHash = string.Empty;
Auth auth;
if (string.IsNullOrEmpty(secondaryUid))
{
db.Auth.Remove(previousAuth);
}
var previousAuth = await db.Auth.FirstOrDefaultAsync(u => u.UserUID == existingLodestoneAuth.User.UID);
if (previousAuth != null)
{
db.Auth.Remove(previousAuth);
}
var computedHash = StringUtils.Sha256String(StringUtils.GenerateRandomString(64) + DateTime.UtcNow.ToString());
var auth = new Auth()
computedHash = StringUtils.Sha256String(StringUtils.GenerateRandomString(64) + DateTime.UtcNow.ToString());
auth = new Auth()
{
HashedKey = StringUtils.Sha256String(computedHash),
User = existingLodestoneAuth.User,
};
await db.Auth.AddAsync(auth).ConfigureAwait(false);
}
else
{
HashedKey = StringUtils.Sha256String(computedHash),
User = existingLodestoneAuth.User,
};
var previousAuth = await db.Auth.Include(u => u.User).FirstOrDefaultAsync(u => u.PrimaryUserUID == existingLodestoneAuth.User.UID && u.UserUID == secondaryUid).ConfigureAwait(false);
if (previousAuth == null)
{
embed.WithTitle("Recovery failed");
embed.WithDescription("This DiscordID has no secondary UID " + secondaryUid);
return embed.Build();
}
db.Auth.Remove(previousAuth);
computedHash = StringUtils.Sha256String(StringUtils.GenerateRandomString(64) + DateTime.UtcNow.ToString());
auth = new Auth()
{
HashedKey = StringUtils.Sha256String(computedHash),
User = previousAuth.User,
PrimaryUserUID = existingLodestoneAuth.User.UID
};
}
embed.WithTitle("Recovery successful");
embed.WithDescription("This is your new private secret key. Do not share this private secret key with anyone. **If you lose it, it is irrevocably lost.**"
@@ -641,7 +839,7 @@ public class MareModule : InteractionModuleBase
return lodestoneId;
}
private async Task<EmbedBuilder> HandleVanityUid(EmbedBuilder eb, ulong id, string newUid)
private async Task<EmbedBuilder> HandleVanityUid(EmbedBuilder eb, ulong id, string newUid, string? secondaryUid)
{
if (_botServices.LastVanityChange.TryGetValue(id, out var lastChange))
{
@@ -681,15 +879,38 @@ public class MareModule : InteractionModuleBase
return eb;
}
var user = lodestoneUser.User;
user.Alias = newUid;
db.Update(user);
if (secondaryUid != null)
{
var secondaryUser = await db.Auth.Include(u => u.PrimaryUser).Include(u => u.User)
.SingleOrDefaultAsync(u => u.UserUID == secondaryUid && u.PrimaryUserUID == lodestoneUser.User.UID).ConfigureAwait(false);
if (secondaryUser == null)
{
eb.WithTitle("No secondary UID found");
eb.WithDescription($"Did not find a secondary UID {secondaryUid} attached to your primary UID {lodestoneUser.User.UID}");
return eb;
}
secondaryUser.User.Alias = newUid;
db.Update(secondaryUser);
eb.WithTitle("Vanity UID set");
eb.WithDescription($"Your Vanity UID for the secondary UID {secondaryUid} was set to **{newUid}**."
+ Environment.NewLine + "For those changes to apply you will have to reconnect to Mare.");
}
else
{
var user = lodestoneUser.User;
user.Alias = newUid;
db.Update(user);
eb.WithTitle("Vanity UID set");
eb.WithDescription("Your Vanity UID was set to **" + newUid + "**."
+ Environment.NewLine + "For those changes to apply you will have to reconnect to Mare.");
}
await db.SaveChangesAsync();
_botServices.LastVanityChange[id] = DateTime.UtcNow;
eb.WithTitle("Vanity UID set");
eb.WithDescription("Your Vanity UID was set to **" + newUid + "**." + Environment.NewLine + "For those changes to apply you will have to reconnect to Mare.");
return eb;
}

View File

@@ -0,0 +1,544 @@
// <auto-generated />
using System;
using MareSynchronosShared.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace MareSynchronosServer.Migrations
{
[DbContext(typeof(MareDbContext))]
[Migration("20230131193425_AddPrimaryUserToAuth")]
partial class AddPrimaryUserToAuth
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("MareSynchronosShared.Models.Auth", b =>
{
b.Property<string>("HashedKey")
.HasMaxLength(64)
.HasColumnType("character varying(64)")
.HasColumnName("hashed_key");
b.Property<bool>("IsBanned")
.HasColumnType("boolean")
.HasColumnName("is_banned");
b.Property<string>("PrimaryUserUID")
.HasColumnType("character varying(10)")
.HasColumnName("primary_user_uid");
b.Property<string>("UserUID")
.HasColumnType("character varying(10)")
.HasColumnName("user_uid");
b.HasKey("HashedKey")
.HasName("pk_auth");
b.HasIndex("PrimaryUserUID")
.HasDatabaseName("ix_auth_primary_user_uid");
b.HasIndex("UserUID")
.HasDatabaseName("ix_auth_user_uid");
b.ToTable("auth", (string)null);
});
modelBuilder.Entity("MareSynchronosShared.Models.Banned", b =>
{
b.Property<string>("CharacterIdentification")
.HasMaxLength(100)
.HasColumnType("character varying(100)")
.HasColumnName("character_identification");
b.Property<string>("Reason")
.HasColumnType("text")
.HasColumnName("reason");
b.Property<byte[]>("Timestamp")
.IsConcurrencyToken()
.ValueGeneratedOnAddOrUpdate()
.HasColumnType("bytea")
.HasColumnName("timestamp");
b.HasKey("CharacterIdentification")
.HasName("pk_banned_users");
b.ToTable("banned_users", (string)null);
});
modelBuilder.Entity("MareSynchronosShared.Models.BannedRegistrations", b =>
{
b.Property<string>("DiscordIdOrLodestoneAuth")
.HasMaxLength(100)
.HasColumnType("character varying(100)")
.HasColumnName("discord_id_or_lodestone_auth");
b.HasKey("DiscordIdOrLodestoneAuth")
.HasName("pk_banned_registrations");
b.ToTable("banned_registrations", (string)null);
});
modelBuilder.Entity("MareSynchronosShared.Models.ClientPair", b =>
{
b.Property<string>("UserUID")
.HasMaxLength(10)
.HasColumnType("character varying(10)")
.HasColumnName("user_uid");
b.Property<string>("OtherUserUID")
.HasMaxLength(10)
.HasColumnType("character varying(10)")
.HasColumnName("other_user_uid");
b.Property<bool>("AllowReceivingMessages")
.HasColumnType("boolean")
.HasColumnName("allow_receiving_messages");
b.Property<bool>("IsPaused")
.HasColumnType("boolean")
.HasColumnName("is_paused");
b.Property<byte[]>("Timestamp")
.IsConcurrencyToken()
.ValueGeneratedOnAddOrUpdate()
.HasColumnType("bytea")
.HasColumnName("timestamp");
b.HasKey("UserUID", "OtherUserUID")
.HasName("pk_client_pairs");
b.HasIndex("OtherUserUID")
.HasDatabaseName("ix_client_pairs_other_user_uid");
b.HasIndex("UserUID")
.HasDatabaseName("ix_client_pairs_user_uid");
b.ToTable("client_pairs", (string)null);
});
modelBuilder.Entity("MareSynchronosShared.Models.FileCache", b =>
{
b.Property<string>("Hash")
.HasMaxLength(40)
.HasColumnType("character varying(40)")
.HasColumnName("hash");
b.Property<long>("Size")
.HasColumnType("bigint")
.HasColumnName("size");
b.Property<byte[]>("Timestamp")
.IsConcurrencyToken()
.ValueGeneratedOnAddOrUpdate()
.HasColumnType("bytea")
.HasColumnName("timestamp");
b.Property<DateTime>("UploadDate")
.HasColumnType("timestamp with time zone")
.HasColumnName("upload_date");
b.Property<bool>("Uploaded")
.HasColumnType("boolean")
.HasColumnName("uploaded");
b.Property<string>("UploaderUID")
.HasMaxLength(10)
.HasColumnType("character varying(10)")
.HasColumnName("uploader_uid");
b.HasKey("Hash")
.HasName("pk_file_caches");
b.HasIndex("UploaderUID")
.HasDatabaseName("ix_file_caches_uploader_uid");
b.ToTable("file_caches", (string)null);
});
modelBuilder.Entity("MareSynchronosShared.Models.ForbiddenUploadEntry", b =>
{
b.Property<string>("Hash")
.HasMaxLength(40)
.HasColumnType("character varying(40)")
.HasColumnName("hash");
b.Property<string>("ForbiddenBy")
.HasMaxLength(100)
.HasColumnType("character varying(100)")
.HasColumnName("forbidden_by");
b.Property<byte[]>("Timestamp")
.IsConcurrencyToken()
.ValueGeneratedOnAddOrUpdate()
.HasColumnType("bytea")
.HasColumnName("timestamp");
b.HasKey("Hash")
.HasName("pk_forbidden_upload_entries");
b.ToTable("forbidden_upload_entries", (string)null);
});
modelBuilder.Entity("MareSynchronosShared.Models.Group", b =>
{
b.Property<string>("GID")
.HasMaxLength(20)
.HasColumnType("character varying(20)")
.HasColumnName("gid");
b.Property<string>("Alias")
.HasMaxLength(50)
.HasColumnType("character varying(50)")
.HasColumnName("alias");
b.Property<bool>("DisableAnimations")
.HasColumnType("boolean")
.HasColumnName("disable_animations");
b.Property<bool>("DisableSounds")
.HasColumnType("boolean")
.HasColumnName("disable_sounds");
b.Property<string>("HashedPassword")
.HasColumnType("text")
.HasColumnName("hashed_password");
b.Property<bool>("InvitesEnabled")
.HasColumnType("boolean")
.HasColumnName("invites_enabled");
b.Property<string>("OwnerUID")
.HasColumnType("character varying(10)")
.HasColumnName("owner_uid");
b.HasKey("GID")
.HasName("pk_groups");
b.HasIndex("OwnerUID")
.HasDatabaseName("ix_groups_owner_uid");
b.ToTable("groups", (string)null);
});
modelBuilder.Entity("MareSynchronosShared.Models.GroupBan", b =>
{
b.Property<string>("GroupGID")
.HasColumnType("character varying(20)")
.HasColumnName("group_gid");
b.Property<string>("BannedUserUID")
.HasColumnType("character varying(10)")
.HasColumnName("banned_user_uid");
b.Property<string>("BannedByUID")
.HasColumnType("character varying(10)")
.HasColumnName("banned_by_uid");
b.Property<DateTime>("BannedOn")
.HasColumnType("timestamp with time zone")
.HasColumnName("banned_on");
b.Property<string>("BannedReason")
.HasColumnType("text")
.HasColumnName("banned_reason");
b.HasKey("GroupGID", "BannedUserUID")
.HasName("pk_group_bans");
b.HasIndex("BannedByUID")
.HasDatabaseName("ix_group_bans_banned_by_uid");
b.HasIndex("BannedUserUID")
.HasDatabaseName("ix_group_bans_banned_user_uid");
b.HasIndex("GroupGID")
.HasDatabaseName("ix_group_bans_group_gid");
b.ToTable("group_bans", (string)null);
});
modelBuilder.Entity("MareSynchronosShared.Models.GroupPair", b =>
{
b.Property<string>("GroupGID")
.HasColumnType("character varying(20)")
.HasColumnName("group_gid");
b.Property<string>("GroupUserUID")
.HasColumnType("character varying(10)")
.HasColumnName("group_user_uid");
b.Property<bool>("DisableAnimations")
.HasColumnType("boolean")
.HasColumnName("disable_animations");
b.Property<bool>("DisableSounds")
.HasColumnType("boolean")
.HasColumnName("disable_sounds");
b.Property<bool>("IsModerator")
.HasColumnType("boolean")
.HasColumnName("is_moderator");
b.Property<bool>("IsPaused")
.HasColumnType("boolean")
.HasColumnName("is_paused");
b.Property<bool>("IsPinned")
.HasColumnType("boolean")
.HasColumnName("is_pinned");
b.HasKey("GroupGID", "GroupUserUID")
.HasName("pk_group_pairs");
b.HasIndex("GroupGID")
.HasDatabaseName("ix_group_pairs_group_gid");
b.HasIndex("GroupUserUID")
.HasDatabaseName("ix_group_pairs_group_user_uid");
b.ToTable("group_pairs", (string)null);
});
modelBuilder.Entity("MareSynchronosShared.Models.GroupTempInvite", b =>
{
b.Property<string>("GroupGID")
.HasColumnType("character varying(20)")
.HasColumnName("group_gid");
b.Property<string>("Invite")
.HasMaxLength(64)
.HasColumnType("character varying(64)")
.HasColumnName("invite");
b.Property<DateTime>("ExpirationDate")
.HasColumnType("timestamp with time zone")
.HasColumnName("expiration_date");
b.HasKey("GroupGID", "Invite")
.HasName("pk_group_temp_invites");
b.HasIndex("GroupGID")
.HasDatabaseName("ix_group_temp_invites_group_gid");
b.HasIndex("Invite")
.HasDatabaseName("ix_group_temp_invites_invite");
b.ToTable("group_temp_invites", (string)null);
});
modelBuilder.Entity("MareSynchronosShared.Models.LodeStoneAuth", b =>
{
b.Property<decimal>("DiscordId")
.ValueGeneratedOnAdd()
.HasColumnType("numeric(20,0)")
.HasColumnName("discord_id");
b.Property<string>("HashedLodestoneId")
.HasMaxLength(100)
.HasColumnType("character varying(100)")
.HasColumnName("hashed_lodestone_id");
b.Property<string>("LodestoneAuthString")
.HasMaxLength(100)
.HasColumnType("character varying(100)")
.HasColumnName("lodestone_auth_string");
b.Property<DateTime?>("StartedAt")
.HasColumnType("timestamp with time zone")
.HasColumnName("started_at");
b.Property<string>("UserUID")
.HasColumnType("character varying(10)")
.HasColumnName("user_uid");
b.HasKey("DiscordId")
.HasName("pk_lodestone_auth");
b.HasIndex("UserUID")
.HasDatabaseName("ix_lodestone_auth_user_uid");
b.ToTable("lodestone_auth", (string)null);
});
modelBuilder.Entity("MareSynchronosShared.Models.User", b =>
{
b.Property<string>("UID")
.HasMaxLength(10)
.HasColumnType("character varying(10)")
.HasColumnName("uid");
b.Property<string>("Alias")
.HasMaxLength(15)
.HasColumnType("character varying(15)")
.HasColumnName("alias");
b.Property<bool>("IsAdmin")
.HasColumnType("boolean")
.HasColumnName("is_admin");
b.Property<bool>("IsModerator")
.HasColumnType("boolean")
.HasColumnName("is_moderator");
b.Property<DateTime>("LastLoggedIn")
.HasColumnType("timestamp with time zone")
.HasColumnName("last_logged_in");
b.Property<byte[]>("Timestamp")
.IsConcurrencyToken()
.ValueGeneratedOnAddOrUpdate()
.HasColumnType("bytea")
.HasColumnName("timestamp");
b.HasKey("UID")
.HasName("pk_users");
b.ToTable("users", (string)null);
});
modelBuilder.Entity("MareSynchronosShared.Models.Auth", b =>
{
b.HasOne("MareSynchronosShared.Models.User", "PrimaryUser")
.WithMany()
.HasForeignKey("PrimaryUserUID")
.HasConstraintName("fk_auth_users_primary_user_temp_id");
b.HasOne("MareSynchronosShared.Models.User", "User")
.WithMany()
.HasForeignKey("UserUID")
.HasConstraintName("fk_auth_users_user_temp_id1");
b.Navigation("PrimaryUser");
b.Navigation("User");
});
modelBuilder.Entity("MareSynchronosShared.Models.ClientPair", b =>
{
b.HasOne("MareSynchronosShared.Models.User", "OtherUser")
.WithMany()
.HasForeignKey("OtherUserUID")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_client_pairs_users_other_user_temp_id2");
b.HasOne("MareSynchronosShared.Models.User", "User")
.WithMany()
.HasForeignKey("UserUID")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_client_pairs_users_user_temp_id3");
b.Navigation("OtherUser");
b.Navigation("User");
});
modelBuilder.Entity("MareSynchronosShared.Models.FileCache", b =>
{
b.HasOne("MareSynchronosShared.Models.User", "Uploader")
.WithMany()
.HasForeignKey("UploaderUID")
.HasConstraintName("fk_file_caches_users_uploader_uid");
b.Navigation("Uploader");
});
modelBuilder.Entity("MareSynchronosShared.Models.Group", b =>
{
b.HasOne("MareSynchronosShared.Models.User", "Owner")
.WithMany()
.HasForeignKey("OwnerUID")
.HasConstraintName("fk_groups_users_owner_temp_id8");
b.Navigation("Owner");
});
modelBuilder.Entity("MareSynchronosShared.Models.GroupBan", b =>
{
b.HasOne("MareSynchronosShared.Models.User", "BannedBy")
.WithMany()
.HasForeignKey("BannedByUID")
.HasConstraintName("fk_group_bans_users_banned_by_temp_id5");
b.HasOne("MareSynchronosShared.Models.User", "BannedUser")
.WithMany()
.HasForeignKey("BannedUserUID")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_group_bans_users_banned_user_temp_id6");
b.HasOne("MareSynchronosShared.Models.Group", "Group")
.WithMany()
.HasForeignKey("GroupGID")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_group_bans_groups_group_temp_id");
b.Navigation("BannedBy");
b.Navigation("BannedUser");
b.Navigation("Group");
});
modelBuilder.Entity("MareSynchronosShared.Models.GroupPair", b =>
{
b.HasOne("MareSynchronosShared.Models.Group", "Group")
.WithMany()
.HasForeignKey("GroupGID")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_group_pairs_groups_group_temp_id1");
b.HasOne("MareSynchronosShared.Models.User", "GroupUser")
.WithMany()
.HasForeignKey("GroupUserUID")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_group_pairs_users_group_user_temp_id7");
b.Navigation("Group");
b.Navigation("GroupUser");
});
modelBuilder.Entity("MareSynchronosShared.Models.GroupTempInvite", b =>
{
b.HasOne("MareSynchronosShared.Models.Group", "Group")
.WithMany()
.HasForeignKey("GroupGID")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_group_temp_invites_groups_group_gid");
b.Navigation("Group");
});
modelBuilder.Entity("MareSynchronosShared.Models.LodeStoneAuth", b =>
{
b.HasOne("MareSynchronosShared.Models.User", "User")
.WithMany()
.HasForeignKey("UserUID")
.HasConstraintName("fk_lodestone_auth_users_user_uid");
b.Navigation("User");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,210 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace MareSynchronosServer.Migrations
{
/// <inheritdoc />
public partial class AddPrimaryUserToAuth : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "fk_auth_users_user_temp_id",
table: "auth");
migrationBuilder.DropForeignKey(
name: "fk_client_pairs_users_other_user_temp_id1",
table: "client_pairs");
migrationBuilder.DropForeignKey(
name: "fk_client_pairs_users_user_temp_id2",
table: "client_pairs");
migrationBuilder.DropForeignKey(
name: "fk_group_bans_users_banned_by_temp_id4",
table: "group_bans");
migrationBuilder.DropForeignKey(
name: "fk_group_bans_users_banned_user_temp_id5",
table: "group_bans");
migrationBuilder.DropForeignKey(
name: "fk_group_pairs_users_group_user_temp_id6",
table: "group_pairs");
migrationBuilder.DropForeignKey(
name: "fk_groups_users_owner_temp_id7",
table: "groups");
migrationBuilder.AddColumn<string>(
name: "primary_user_uid",
table: "auth",
type: "character varying(10)",
nullable: true);
migrationBuilder.CreateIndex(
name: "ix_auth_primary_user_uid",
table: "auth",
column: "primary_user_uid");
migrationBuilder.AddForeignKey(
name: "fk_auth_users_primary_user_temp_id",
table: "auth",
column: "primary_user_uid",
principalTable: "users",
principalColumn: "uid");
migrationBuilder.AddForeignKey(
name: "fk_auth_users_user_temp_id1",
table: "auth",
column: "user_uid",
principalTable: "users",
principalColumn: "uid");
migrationBuilder.AddForeignKey(
name: "fk_client_pairs_users_other_user_temp_id2",
table: "client_pairs",
column: "other_user_uid",
principalTable: "users",
principalColumn: "uid",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "fk_client_pairs_users_user_temp_id3",
table: "client_pairs",
column: "user_uid",
principalTable: "users",
principalColumn: "uid",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "fk_group_bans_users_banned_by_temp_id5",
table: "group_bans",
column: "banned_by_uid",
principalTable: "users",
principalColumn: "uid");
migrationBuilder.AddForeignKey(
name: "fk_group_bans_users_banned_user_temp_id6",
table: "group_bans",
column: "banned_user_uid",
principalTable: "users",
principalColumn: "uid",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "fk_group_pairs_users_group_user_temp_id7",
table: "group_pairs",
column: "group_user_uid",
principalTable: "users",
principalColumn: "uid",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "fk_groups_users_owner_temp_id8",
table: "groups",
column: "owner_uid",
principalTable: "users",
principalColumn: "uid");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "fk_auth_users_primary_user_temp_id",
table: "auth");
migrationBuilder.DropForeignKey(
name: "fk_auth_users_user_temp_id1",
table: "auth");
migrationBuilder.DropForeignKey(
name: "fk_client_pairs_users_other_user_temp_id2",
table: "client_pairs");
migrationBuilder.DropForeignKey(
name: "fk_client_pairs_users_user_temp_id3",
table: "client_pairs");
migrationBuilder.DropForeignKey(
name: "fk_group_bans_users_banned_by_temp_id5",
table: "group_bans");
migrationBuilder.DropForeignKey(
name: "fk_group_bans_users_banned_user_temp_id6",
table: "group_bans");
migrationBuilder.DropForeignKey(
name: "fk_group_pairs_users_group_user_temp_id7",
table: "group_pairs");
migrationBuilder.DropForeignKey(
name: "fk_groups_users_owner_temp_id8",
table: "groups");
migrationBuilder.DropIndex(
name: "ix_auth_primary_user_uid",
table: "auth");
migrationBuilder.DropColumn(
name: "primary_user_uid",
table: "auth");
migrationBuilder.AddForeignKey(
name: "fk_auth_users_user_temp_id",
table: "auth",
column: "user_uid",
principalTable: "users",
principalColumn: "uid");
migrationBuilder.AddForeignKey(
name: "fk_client_pairs_users_other_user_temp_id1",
table: "client_pairs",
column: "other_user_uid",
principalTable: "users",
principalColumn: "uid",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "fk_client_pairs_users_user_temp_id2",
table: "client_pairs",
column: "user_uid",
principalTable: "users",
principalColumn: "uid",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "fk_group_bans_users_banned_by_temp_id4",
table: "group_bans",
column: "banned_by_uid",
principalTable: "users",
principalColumn: "uid");
migrationBuilder.AddForeignKey(
name: "fk_group_bans_users_banned_user_temp_id5",
table: "group_bans",
column: "banned_user_uid",
principalTable: "users",
principalColumn: "uid",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "fk_group_pairs_users_group_user_temp_id6",
table: "group_pairs",
column: "group_user_uid",
principalTable: "users",
principalColumn: "uid",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "fk_groups_users_owner_temp_id7",
table: "groups",
column: "owner_uid",
principalTable: "users",
principalColumn: "uid");
}
}
}

View File

@@ -33,6 +33,10 @@ namespace MareSynchronosServer.Migrations
.HasColumnType("boolean")
.HasColumnName("is_banned");
b.Property<string>("PrimaryUserUID")
.HasColumnType("character varying(10)")
.HasColumnName("primary_user_uid");
b.Property<string>("UserUID")
.HasColumnType("character varying(10)")
.HasColumnName("user_uid");
@@ -40,6 +44,9 @@ namespace MareSynchronosServer.Migrations
b.HasKey("HashedKey")
.HasName("pk_auth");
b.HasIndex("PrimaryUserUID")
.HasDatabaseName("ix_auth_primary_user_uid");
b.HasIndex("UserUID")
.HasDatabaseName("ix_auth_user_uid");
@@ -402,10 +409,17 @@ namespace MareSynchronosServer.Migrations
modelBuilder.Entity("MareSynchronosShared.Models.Auth", b =>
{
b.HasOne("MareSynchronosShared.Models.User", "PrimaryUser")
.WithMany()
.HasForeignKey("PrimaryUserUID")
.HasConstraintName("fk_auth_users_primary_user_temp_id");
b.HasOne("MareSynchronosShared.Models.User", "User")
.WithMany()
.HasForeignKey("UserUID")
.HasConstraintName("fk_auth_users_user_temp_id");
.HasConstraintName("fk_auth_users_user_temp_id1");
b.Navigation("PrimaryUser");
b.Navigation("User");
});
@@ -417,14 +431,14 @@ namespace MareSynchronosServer.Migrations
.HasForeignKey("OtherUserUID")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_client_pairs_users_other_user_temp_id1");
.HasConstraintName("fk_client_pairs_users_other_user_temp_id2");
b.HasOne("MareSynchronosShared.Models.User", "User")
.WithMany()
.HasForeignKey("UserUID")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_client_pairs_users_user_temp_id2");
.HasConstraintName("fk_client_pairs_users_user_temp_id3");
b.Navigation("OtherUser");
@@ -446,7 +460,7 @@ namespace MareSynchronosServer.Migrations
b.HasOne("MareSynchronosShared.Models.User", "Owner")
.WithMany()
.HasForeignKey("OwnerUID")
.HasConstraintName("fk_groups_users_owner_temp_id7");
.HasConstraintName("fk_groups_users_owner_temp_id8");
b.Navigation("Owner");
});
@@ -456,14 +470,14 @@ namespace MareSynchronosServer.Migrations
b.HasOne("MareSynchronosShared.Models.User", "BannedBy")
.WithMany()
.HasForeignKey("BannedByUID")
.HasConstraintName("fk_group_bans_users_banned_by_temp_id4");
.HasConstraintName("fk_group_bans_users_banned_by_temp_id5");
b.HasOne("MareSynchronosShared.Models.User", "BannedUser")
.WithMany()
.HasForeignKey("BannedUserUID")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_group_bans_users_banned_user_temp_id5");
.HasConstraintName("fk_group_bans_users_banned_user_temp_id6");
b.HasOne("MareSynchronosShared.Models.Group", "Group")
.WithMany()
@@ -493,7 +507,7 @@ namespace MareSynchronosServer.Migrations
.HasForeignKey("GroupUserUID")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_group_pairs_users_group_user_temp_id6");
.HasConstraintName("fk_group_pairs_users_group_user_temp_id7");
b.Navigation("Group");

View File

@@ -11,4 +11,6 @@ public class Auth
public string UserUID { get; set; }
public User User { get; set; }
public bool IsBanned { get; set; }
public string? PrimaryUserUID { get; set; }
public User? PrimaryUser { get; set; }
}