diff --git a/LightlessAPI b/LightlessAPI index 3a69c94..4ce70be 160000 --- a/LightlessAPI +++ b/LightlessAPI @@ -1 +1 @@ -Subproject commit 3a69c94f7fb10a0cfc51c857b2194640fda48140 +Subproject commit 4ce70bee8354d0c96d73e65312d39a826810dc60 diff --git a/LightlessSyncServer/LightlessSyncAuthService/Controllers/AuthControllerBase.cs b/LightlessSyncServer/LightlessSyncAuthService/Controllers/AuthControllerBase.cs index d207db6..b47f38d 100644 --- a/LightlessSyncServer/LightlessSyncAuthService/Controllers/AuthControllerBase.cs +++ b/LightlessSyncServer/LightlessSyncAuthService/Controllers/AuthControllerBase.cs @@ -121,6 +121,7 @@ public abstract class AuthControllerBase : Controller { CharacterIdentification = charaIdent, Reason = "Autobanned CharacterIdent (" + uid + ")", + BannedUid = uid, }); } diff --git a/LightlessSyncServer/LightlessSyncAuthService/Startup.cs b/LightlessSyncServer/LightlessSyncAuthService/Startup.cs index 385fa32..20d8d89 100644 --- a/LightlessSyncServer/LightlessSyncAuthService/Startup.cs +++ b/LightlessSyncServer/LightlessSyncAuthService/Startup.cs @@ -3,8 +3,6 @@ using LightlessSyncShared.Metrics; using LightlessSyncShared.Services; using LightlessSyncShared.Utils; using Microsoft.AspNetCore.Mvc.Controllers; -using StackExchange.Redis.Extensions.Core.Configuration; -using StackExchange.Redis.Extensions.System.Text.Json; using StackExchange.Redis; using System.Net; using LightlessSyncAuthService.Services; @@ -17,7 +15,6 @@ using LightlessSyncShared.Data; using Microsoft.EntityFrameworkCore; using Prometheus; using LightlessSyncShared.Utils.Configuration; -using StackExchange.Redis.Extensions.Core.Abstractions; namespace LightlessSyncAuthService; diff --git a/LightlessSyncServer/LightlessSyncServer/Controllers/UserController.cs b/LightlessSyncServer/LightlessSyncServer/Controllers/UserController.cs new file mode 100644 index 0000000..0084566 --- /dev/null +++ b/LightlessSyncServer/LightlessSyncServer/Controllers/UserController.cs @@ -0,0 +1,99 @@ +using LightlessSync.API.Dto.User; +using LightlessSync.API.Routes; +using LightlessSyncShared.Data; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; + +namespace LightlessSyncAuthService.Controllers; + +[Route(LightlessAuth.User)] +[Authorize(Policy = "Internal")] +public class UserController : Controller +{ + protected readonly ILogger Logger; + protected readonly IDbContextFactory LightlessDbContextFactory; + public UserController(ILogger logger, IDbContextFactory lightlessDbContext) + { + Logger = logger; + LightlessDbContextFactory = lightlessDbContext; + } + + [Route(LightlessAuth.Ban_Uid)] + [HttpPost] + public async Task MarkForBanUid([FromBody] BanRequest request) + { + using var dbContext = await LightlessDbContextFactory.CreateDbContextAsync(); + + Logger.LogInformation("Banning user with UID {UID}", request.Uid); + + //Mark User as banned, and not marked for ban + var auth = await dbContext.Auth.FirstOrDefaultAsync(f => f.UserUID == request.Uid); + if (auth != null) + { + auth.MarkForBan = true; + } + + await dbContext.SaveChangesAsync(); + } + + [Route(LightlessAuth.User_Unban_Uid)] + [HttpPost] + public async Task UnBanUserByUid([FromBody] UnbanRequest request) + { + using var dbContext = await LightlessDbContextFactory.CreateDbContextAsync(); + + Logger.LogInformation("Unbanning user with UID {UID}", request.Uid); + + //Mark User as not banned, and not marked for ban (if marked) + var auth = await dbContext.Auth.FirstOrDefaultAsync(f => f.UserUID == request.Uid); + if (auth != null) + { + auth.IsBanned = false; + auth.MarkForBan = false; + } + + // Remove all bans associated with this user + var bannedFromLightlessIds = dbContext.BannedUsers.Where(b => b.BannedUid == request.Uid); + dbContext.BannedUsers.RemoveRange(bannedFromLightlessIds); + + // Remove all character/discord bans associated with this user + var lodestoneAuths = dbContext.LodeStoneAuth.Where(l => l.User != null && l.User.UID == request.Uid).ToList(); + foreach (var lodestoneAuth in lodestoneAuths) + { + var bannedRegs = dbContext.BannedRegistrations.Where(b => b.DiscordIdOrLodestoneAuth == lodestoneAuth.HashedLodestoneId || b.DiscordIdOrLodestoneAuth == lodestoneAuth.DiscordId.ToString()); + dbContext.BannedRegistrations.RemoveRange(bannedRegs); + } + + await dbContext.SaveChangesAsync(); + } + + [Route(LightlessAuth.User_Unban_Discord)] + [HttpPost] + public async Task UnBanUserByDiscordId([FromBody] UnbanRequest request) + { + Logger.LogInformation("Unbanning user with discordId: {discordId}", request.DiscordId); + using var dbContext = await LightlessDbContextFactory.CreateDbContextAsync(); + + var userByDiscord = await dbContext.LodeStoneAuth.Include(l => l.User).FirstOrDefaultAsync(l => l.DiscordId.ToString() == request.DiscordId); + + if (userByDiscord?.User == null) + { + Logger.LogInformation("Unbanning user with discordId: {discordId} but no user found", request.DiscordId); + return; + } + var bannedRegs = dbContext.BannedRegistrations.Where(b => b.DiscordIdOrLodestoneAuth == request.DiscordId || b.DiscordIdOrLodestoneAuth == userByDiscord.HashedLodestoneId); + //Mark User as not banned, and not marked for ban (if marked) + var auth = await dbContext.Auth.FirstOrDefaultAsync(f => f.UserUID == userByDiscord.User.UID); + if (auth != null) + { + auth.IsBanned = false; + auth.MarkForBan = false; + } + // Remove all bans associated with this user + var bannedFromLightlessIds = dbContext.BannedUsers.Where(b => b.BannedUid == auth.UserUID || b.BannedUid == auth.PrimaryUserUID); + dbContext.BannedUsers.RemoveRange(bannedFromLightlessIds); + + await dbContext.SaveChangesAsync(); + } +} \ No newline at end of file diff --git a/LightlessSyncServer/LightlessSyncServer/Startup.cs b/LightlessSyncServer/LightlessSyncServer/Startup.cs index 4a2a2ba..d9bab3f 100644 --- a/LightlessSyncServer/LightlessSyncServer/Startup.cs +++ b/LightlessSyncServer/LightlessSyncServer/Startup.cs @@ -1,29 +1,30 @@ -using Microsoft.EntityFrameworkCore; -using LightlessSyncServer.Hubs; -using Microsoft.AspNetCore.Http.Connections; -using Microsoft.AspNetCore.SignalR; -using Microsoft.AspNetCore.Authorization; using AspNetCoreRateLimit; +using LightlessSync.API.SignalR; +using LightlessSyncAuthService.Controllers; +using LightlessSyncServer.Controllers; +using LightlessSyncServer.Hubs; +using LightlessSyncServer.Services; using LightlessSyncShared.Data; using LightlessSyncShared.Metrics; -using LightlessSyncServer.Services; -using LightlessSyncShared.Utils; +using LightlessSyncShared.RequirementHandlers; using LightlessSyncShared.Services; -using Prometheus; -using Microsoft.AspNetCore.Authentication.JwtBearer; -using Microsoft.IdentityModel.Tokens; -using System.Text; -using StackExchange.Redis; -using StackExchange.Redis.Extensions.Core.Configuration; -using System.Net; -using StackExchange.Redis.Extensions.System.Text.Json; -using LightlessSync.API.SignalR; +using LightlessSyncShared.Utils; +using LightlessSyncShared.Utils.Configuration; using MessagePack; using MessagePack.Resolvers; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http.Connections; using Microsoft.AspNetCore.Mvc.Controllers; -using LightlessSyncServer.Controllers; -using LightlessSyncShared.RequirementHandlers; -using LightlessSyncShared.Utils.Configuration; +using Microsoft.AspNetCore.SignalR; +using Microsoft.EntityFrameworkCore; +using Microsoft.IdentityModel.Tokens; +using Prometheus; +using StackExchange.Redis; +using StackExchange.Redis.Extensions.Core.Configuration; +using StackExchange.Redis.Extensions.System.Text.Json; +using System.Net; +using System.Text; namespace LightlessSyncServer; @@ -71,7 +72,7 @@ public class Startup a.FeatureProviders.Remove(a.FeatureProviders.OfType().First()); if (lightlessConfig.GetValue(nameof(ServerConfiguration.MainServerAddress), defaultValue: null) == null) { - a.FeatureProviders.Add(new AllowedControllersFeatureProvider(typeof(LightlessServerConfigurationController), typeof(LightlessBaseConfigurationController), typeof(ClientMessageController))); + a.FeatureProviders.Add(new AllowedControllersFeatureProvider(typeof(LightlessServerConfigurationController), typeof(LightlessBaseConfigurationController), typeof(ClientMessageController), typeof(UserController))); } else { diff --git a/LightlessSyncServer/LightlessSyncServerTest/Discord/DiscordBotTest.cs b/LightlessSyncServer/LightlessSyncServerTest/Discord/DiscordBotTest.cs index d57ca55..a10b34e 100644 --- a/LightlessSyncServer/LightlessSyncServerTest/Discord/DiscordBotTest.cs +++ b/LightlessSyncServer/LightlessSyncServerTest/Discord/DiscordBotTest.cs @@ -1,5 +1,5 @@ using FluentAssertions; -using LightlessSyncServer.Discord; +using LightlessSyncServices.Discord; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Primitives; diff --git a/LightlessSyncServer/LightlessSyncServerTest/LightlessSyncServerTest.csproj b/LightlessSyncServer/LightlessSyncServerTest/LightlessSyncServerTest.csproj index 471a7a3..4753c04 100644 --- a/LightlessSyncServer/LightlessSyncServerTest/LightlessSyncServerTest.csproj +++ b/LightlessSyncServer/LightlessSyncServerTest/LightlessSyncServerTest.csproj @@ -1,7 +1,7 @@  - net6.0 + net9.0 enable enable diff --git a/LightlessSyncServer/LightlessSyncServices/Discord/DiscordBot.cs b/LightlessSyncServer/LightlessSyncServices/Discord/DiscordBot.cs index 9fd515f..bbf96c4 100644 --- a/LightlessSyncServer/LightlessSyncServices/Discord/DiscordBot.cs +++ b/LightlessSyncServer/LightlessSyncServices/Discord/DiscordBot.cs @@ -7,7 +7,6 @@ using LightlessSyncShared.Models; using LightlessSyncShared.Services; using LightlessSyncShared.Utils.Configuration; using Microsoft.EntityFrameworkCore; -using Newtonsoft.Json.Linq; using StackExchange.Redis; namespace LightlessSyncServices.Discord; diff --git a/LightlessSyncServer/LightlessSyncServices/Discord/MareModule.cs b/LightlessSyncServer/LightlessSyncServices/Discord/MareModule.cs index e87478a..48d1c03 100644 --- a/LightlessSyncServer/LightlessSyncServices/Discord/MareModule.cs +++ b/LightlessSyncServer/LightlessSyncServices/Discord/MareModule.cs @@ -9,6 +9,7 @@ using LightlessSyncShared.Services; using StackExchange.Redis; using LightlessSync.API.Data.Enum; using LightlessSyncShared.Utils.Configuration; +using LightlessSync.API.Dto.User; namespace LightlessSyncServices.Discord; @@ -106,6 +107,8 @@ public class LightlessModule : InteractionModuleBase using HttpClient c = new HttpClient(); c.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", _serverTokenGenerator.Token); + var testUri = new Uri(_lightlessServicesConfiguration.GetValue + (nameof(ServicesConfiguration.MainServerAddress)), "/msgc/sendMessage"); await c.PostAsJsonAsync( new Uri(_lightlessServicesConfiguration.GetValue(nameof(ServicesConfiguration.MainServerAddress)), "/msgc/sendMessage"), @@ -143,6 +146,134 @@ public class LightlessModule : InteractionModuleBase } } + [SlashCommand("unbanbydiscord", "ADMIN ONLY: Unban a user by their discord ID")] + public async Task UnbanByDiscord([Summary("discord_id", "Discord ID to unban")] string discordId) + { + _logger.LogInformation("SlashCommand:{userId}:{Method}:{params}", + Context.Interaction.User.Id, nameof(UnbanByDiscord), + string.Join(",", new[] { $"{nameof(discordId)}:{discordId}" })); + try + { + using HttpClient c = new HttpClient(); + + c.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", _serverTokenGenerator.Token); + await c.PostAsJsonAsync(new Uri(_lightlessServicesConfiguration.GetValue + (nameof(ServicesConfiguration.MainServerAddress)), "/user/unbanDiscord"), new UnbanRequest(string.Empty, discordId)) + .ConfigureAwait(false); + var discordChannelForMessages = _lightlessServicesConfiguration.GetValueOrDefault(nameof(ServicesConfiguration.DiscordChannelForMessages), null); + if (discordChannelForMessages != null) + { + var discordChannel = await Context.Guild.GetChannelAsync(discordChannelForMessages.Value).ConfigureAwait(false) as IMessageChannel; + if (discordChannel != null) + { + var embedColor = Color.Blue; + + EmbedBuilder eb = new(); + eb.WithTitle("Unban Alert!"); + eb.WithColor(embedColor); + eb.WithDescription(discordId + " has been unbanned"); + + await discordChannel.SendMessageAsync(embed: eb.Build()).ConfigureAwait(false); + } + } + + await RespondAsync("Message sent", ephemeral: true).ConfigureAwait(false); + } + catch (Exception ex) + { + EmbedBuilder eb = new(); + eb.WithTitle("An error occured"); + eb.WithDescription("Please report this: " + Environment.NewLine + ex.Message + Environment.NewLine + ex.StackTrace + Environment.NewLine); + await RespondAsync(embeds: new Embed[] { eb.Build() }, ephemeral: true).ConfigureAwait(false); + } + } + + [SlashCommand("unbanbyuid", "ADMIN ONLY: Unban a user by their uid")] + public async Task UnbanByUID([Summary("uid", "uid to unban")] string uid) + { + _logger.LogInformation("SlashCommand:{userId}:{Method}:{params}", + Context.Interaction.User.Id, nameof(UnbanByUID), + string.Join(",", new[] { $"{nameof(uid)}:{uid}" })); + try + { + using HttpClient c = new HttpClient(); + var testUri = new Uri(_lightlessServicesConfiguration.GetValue + (nameof(ServicesConfiguration.MainServerAddress)), "/user/unbanDiscord"); + + c.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", _serverTokenGenerator.Token); + await c.PostAsJsonAsync(new Uri(_lightlessServicesConfiguration.GetValue + (nameof(ServicesConfiguration.MainServerAddress)), "/user/unbanUID"), new UnbanRequest(uid, string.Empty)) + .ConfigureAwait(false); + var discordChannelForMessages = _lightlessServicesConfiguration.GetValueOrDefault(nameof(ServicesConfiguration.DiscordChannelForMessages), null); + if (discordChannelForMessages != null) + { + var discordChannel = await Context.Guild.GetChannelAsync(discordChannelForMessages.Value).ConfigureAwait(false) as IMessageChannel; + if (discordChannel != null) + { + var embedColor = Color.Blue; + + EmbedBuilder eb = new(); + eb.WithTitle("Unban Alert!"); + eb.WithColor(embedColor); + eb.WithDescription(uid + " has been unbanned"); + + await discordChannel.SendMessageAsync(embed: eb.Build()).ConfigureAwait(false); + } + } + + await RespondAsync("Message sent", ephemeral: true).ConfigureAwait(false); + } + catch (Exception ex) + { + EmbedBuilder eb = new(); + eb.WithTitle("An error occured"); + eb.WithDescription("Please report this: " + Environment.NewLine + ex.Message + Environment.NewLine + ex.StackTrace + Environment.NewLine); + await RespondAsync(embeds: new Embed[] { eb.Build() }, ephemeral: true).ConfigureAwait(false); + } + } + + [SlashCommand("markforban", "ADMIN ONLY: ban a user by their uid")] + public async Task MarkUidForBan([Summary("uid", "uid to ban")] string uid) + { + _logger.LogInformation("SlashCommand:{userId}:{Method}:{params}", + Context.Interaction.User.Id, nameof(MarkUidForBan), + string.Join(",", new[] { $"{nameof(uid)}:{uid}" })); + try + { + using HttpClient c = new HttpClient(); + + c.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", _serverTokenGenerator.Token); + await c.PostAsJsonAsync(new Uri(_lightlessServicesConfiguration.GetValue + (nameof(ServicesConfiguration.MainServerAddress)), "/user/ban"), new BanRequest(uid)) + .ConfigureAwait(false); + var discordChannelForMessages = _lightlessServicesConfiguration.GetValueOrDefault(nameof(ServicesConfiguration.DiscordChannelForMessages), null); + if (discordChannelForMessages != null) + { + var discordChannel = await Context.Guild.GetChannelAsync(discordChannelForMessages.Value).ConfigureAwait(false) as IMessageChannel; + if (discordChannel != null) + { + var embedColor = Color.Blue; + + EmbedBuilder eb = new(); + eb.WithTitle("Ban Alert!"); + eb.WithColor(embedColor); + eb.WithDescription(uid + " has been marked for ban"); + + await discordChannel.SendMessageAsync(embed: eb.Build()).ConfigureAwait(false); + } + } + + await RespondAsync("Message sent", ephemeral: true).ConfigureAwait(false); + } + catch (Exception ex) + { + EmbedBuilder eb = new(); + eb.WithTitle("An error occured"); + eb.WithDescription("Please report this: " + Environment.NewLine + ex.Message + Environment.NewLine + ex.StackTrace + Environment.NewLine); + await RespondAsync(embeds: new Embed[] { eb.Build() }, ephemeral: true).ConfigureAwait(false); + } + } + public async Task HandleUserAdd(string desiredUid, ulong discordUserId) { var embed = new EmbedBuilder(); diff --git a/LightlessSyncServer/LightlessSyncShared/Migrations/20250905192853_AddBannedUid.Designer.cs b/LightlessSyncServer/LightlessSyncShared/Migrations/20250905192853_AddBannedUid.Designer.cs new file mode 100644 index 0000000..5c56f33 --- /dev/null +++ b/LightlessSyncServer/LightlessSyncShared/Migrations/20250905192853_AddBannedUid.Designer.cs @@ -0,0 +1,1098 @@ +// +using System; +using LightlessSyncShared.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 LightlessSyncServer.Migrations +{ + [DbContext(typeof(LightlessDbContext))] + [Migration("20250905192853_AddBannedUid")] + partial class AddBannedUid + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("LightlessSyncShared.Models.Auth", b => + { + b.Property("HashedKey") + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("hashed_key"); + + b.Property("IsBanned") + .HasColumnType("boolean") + .HasColumnName("is_banned"); + + b.Property("MarkForBan") + .HasColumnType("boolean") + .HasColumnName("mark_for_ban"); + + b.Property("PrimaryUserUID") + .HasColumnType("character varying(10)") + .HasColumnName("primary_user_uid"); + + b.Property("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("LightlessSyncShared.Models.Banned", b => + { + b.Property("CharacterIdentification") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("character_identification"); + + b.Property("BannedUid") + .HasColumnType("text") + .HasColumnName("banned_uid"); + + b.Property("Reason") + .HasColumnType("text") + .HasColumnName("reason"); + + b.Property("Timestamp") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("bytea") + .HasColumnName("timestamp"); + + b.HasKey("CharacterIdentification") + .HasName("pk_banned_users"); + + b.ToTable("banned_users", (string)null); + }); + + modelBuilder.Entity("LightlessSyncShared.Models.BannedRegistrations", b => + { + b.Property("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("LightlessSyncShared.Models.CharaData", b => + { + b.Property("Id") + .HasColumnType("text") + .HasColumnName("id"); + + b.Property("UploaderUID") + .HasColumnType("character varying(10)") + .HasColumnName("uploader_uid"); + + b.Property("AccessType") + .HasColumnType("integer") + .HasColumnName("access_type"); + + b.Property("CreatedDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_date"); + + b.Property("CustomizeData") + .HasColumnType("text") + .HasColumnName("customize_data"); + + b.Property("Description") + .HasColumnType("text") + .HasColumnName("description"); + + b.Property("DownloadCount") + .HasColumnType("integer") + .HasColumnName("download_count"); + + b.Property("ExpiryDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("expiry_date"); + + b.Property("GlamourerData") + .HasColumnType("text") + .HasColumnName("glamourer_data"); + + b.Property("ManipulationData") + .HasColumnType("text") + .HasColumnName("manipulation_data"); + + b.Property("ShareType") + .HasColumnType("integer") + .HasColumnName("share_type"); + + b.Property("UpdatedDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_date"); + + b.HasKey("Id", "UploaderUID") + .HasName("pk_chara_data"); + + b.HasIndex("Id") + .HasDatabaseName("ix_chara_data_id"); + + b.HasIndex("UploaderUID") + .HasDatabaseName("ix_chara_data_uploader_uid"); + + b.ToTable("chara_data", (string)null); + }); + + modelBuilder.Entity("LightlessSyncShared.Models.CharaDataAllowance", b => + { + b.Property("ParentId") + .HasColumnType("text") + .HasColumnName("parent_id"); + + b.Property("ParentUploaderUID") + .HasColumnType("character varying(10)") + .HasColumnName("parent_uploader_uid"); + + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AllowedGroupGID") + .HasColumnType("character varying(20)") + .HasColumnName("allowed_group_gid"); + + b.Property("AllowedUserUID") + .HasColumnType("character varying(10)") + .HasColumnName("allowed_user_uid"); + + b.HasKey("ParentId", "ParentUploaderUID", "Id") + .HasName("pk_chara_data_allowance"); + + b.HasIndex("AllowedGroupGID") + .HasDatabaseName("ix_chara_data_allowance_allowed_group_gid"); + + b.HasIndex("AllowedUserUID") + .HasDatabaseName("ix_chara_data_allowance_allowed_user_uid"); + + b.HasIndex("ParentId") + .HasDatabaseName("ix_chara_data_allowance_parent_id"); + + b.ToTable("chara_data_allowance", (string)null); + }); + + modelBuilder.Entity("LightlessSyncShared.Models.CharaDataFile", b => + { + b.Property("ParentId") + .HasColumnType("text") + .HasColumnName("parent_id"); + + b.Property("ParentUploaderUID") + .HasColumnType("character varying(10)") + .HasColumnName("parent_uploader_uid"); + + b.Property("GamePath") + .HasColumnType("text") + .HasColumnName("game_path"); + + b.Property("FileCacheHash") + .HasColumnType("character varying(40)") + .HasColumnName("file_cache_hash"); + + b.HasKey("ParentId", "ParentUploaderUID", "GamePath") + .HasName("pk_chara_data_files"); + + b.HasIndex("FileCacheHash") + .HasDatabaseName("ix_chara_data_files_file_cache_hash"); + + b.HasIndex("ParentId") + .HasDatabaseName("ix_chara_data_files_parent_id"); + + b.ToTable("chara_data_files", (string)null); + }); + + modelBuilder.Entity("LightlessSyncShared.Models.CharaDataFileSwap", b => + { + b.Property("ParentId") + .HasColumnType("text") + .HasColumnName("parent_id"); + + b.Property("ParentUploaderUID") + .HasColumnType("character varying(10)") + .HasColumnName("parent_uploader_uid"); + + b.Property("GamePath") + .HasColumnType("text") + .HasColumnName("game_path"); + + b.Property("FilePath") + .HasColumnType("text") + .HasColumnName("file_path"); + + b.HasKey("ParentId", "ParentUploaderUID", "GamePath") + .HasName("pk_chara_data_file_swaps"); + + b.HasIndex("ParentId") + .HasDatabaseName("ix_chara_data_file_swaps_parent_id"); + + b.ToTable("chara_data_file_swaps", (string)null); + }); + + modelBuilder.Entity("LightlessSyncShared.Models.CharaDataOriginalFile", b => + { + b.Property("ParentId") + .HasColumnType("text") + .HasColumnName("parent_id"); + + b.Property("ParentUploaderUID") + .HasColumnType("character varying(10)") + .HasColumnName("parent_uploader_uid"); + + b.Property("GamePath") + .HasColumnType("text") + .HasColumnName("game_path"); + + b.Property("Hash") + .HasColumnType("text") + .HasColumnName("hash"); + + b.HasKey("ParentId", "ParentUploaderUID", "GamePath") + .HasName("pk_chara_data_orig_files"); + + b.HasIndex("ParentId") + .HasDatabaseName("ix_chara_data_orig_files_parent_id"); + + b.ToTable("chara_data_orig_files", (string)null); + }); + + modelBuilder.Entity("LightlessSyncShared.Models.CharaDataPose", b => + { + b.Property("ParentId") + .HasColumnType("text") + .HasColumnName("parent_id"); + + b.Property("ParentUploaderUID") + .HasColumnType("character varying(10)") + .HasColumnName("parent_uploader_uid"); + + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Description") + .HasColumnType("text") + .HasColumnName("description"); + + b.Property("PoseData") + .HasColumnType("text") + .HasColumnName("pose_data"); + + b.Property("WorldData") + .HasColumnType("text") + .HasColumnName("world_data"); + + b.HasKey("ParentId", "ParentUploaderUID", "Id") + .HasName("pk_chara_data_poses"); + + b.HasIndex("ParentId") + .HasDatabaseName("ix_chara_data_poses_parent_id"); + + b.ToTable("chara_data_poses", (string)null); + }); + + modelBuilder.Entity("LightlessSyncShared.Models.ClientPair", b => + { + b.Property("UserUID") + .HasMaxLength(10) + .HasColumnType("character varying(10)") + .HasColumnName("user_uid"); + + b.Property("OtherUserUID") + .HasMaxLength(10) + .HasColumnType("character varying(10)") + .HasColumnName("other_user_uid"); + + b.Property("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("LightlessSyncShared.Models.FileCache", b => + { + b.Property("Hash") + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("hash"); + + b.Property("RawSize") + .HasColumnType("bigint") + .HasColumnName("raw_size"); + + b.Property("Size") + .HasColumnType("bigint") + .HasColumnName("size"); + + b.Property("Timestamp") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("bytea") + .HasColumnName("timestamp"); + + b.Property("UploadDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("upload_date"); + + b.Property("Uploaded") + .HasColumnType("boolean") + .HasColumnName("uploaded"); + + b.Property("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("LightlessSyncShared.Models.ForbiddenUploadEntry", b => + { + b.Property("Hash") + .HasMaxLength(40) + .HasColumnType("character varying(40)") + .HasColumnName("hash"); + + b.Property("ForbiddenBy") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("forbidden_by"); + + b.Property("Timestamp") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("bytea") + .HasColumnName("timestamp"); + + b.HasKey("Hash") + .HasName("pk_forbidden_upload_entries"); + + b.ToTable("forbidden_upload_entries", (string)null); + }); + + modelBuilder.Entity("LightlessSyncShared.Models.Group", b => + { + b.Property("GID") + .HasMaxLength(20) + .HasColumnType("character varying(20)") + .HasColumnName("gid"); + + b.Property("Alias") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("alias"); + + b.Property("HashedPassword") + .HasColumnType("text") + .HasColumnName("hashed_password"); + + b.Property("InvitesEnabled") + .HasColumnType("boolean") + .HasColumnName("invites_enabled"); + + b.Property("OwnerUID") + .HasColumnType("character varying(10)") + .HasColumnName("owner_uid"); + + b.Property("PreferDisableAnimations") + .HasColumnType("boolean") + .HasColumnName("prefer_disable_animations"); + + b.Property("PreferDisableSounds") + .HasColumnType("boolean") + .HasColumnName("prefer_disable_sounds"); + + b.Property("PreferDisableVFX") + .HasColumnType("boolean") + .HasColumnName("prefer_disable_vfx"); + + b.HasKey("GID") + .HasName("pk_groups"); + + b.HasIndex("OwnerUID") + .HasDatabaseName("ix_groups_owner_uid"); + + b.ToTable("groups", (string)null); + }); + + modelBuilder.Entity("LightlessSyncShared.Models.GroupBan", b => + { + b.Property("GroupGID") + .HasColumnType("character varying(20)") + .HasColumnName("group_gid"); + + b.Property("BannedUserUID") + .HasColumnType("character varying(10)") + .HasColumnName("banned_user_uid"); + + b.Property("BannedByUID") + .HasColumnType("character varying(10)") + .HasColumnName("banned_by_uid"); + + b.Property("BannedOn") + .HasColumnType("timestamp with time zone") + .HasColumnName("banned_on"); + + b.Property("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("LightlessSyncShared.Models.GroupPair", b => + { + b.Property("GroupGID") + .HasColumnType("character varying(20)") + .HasColumnName("group_gid"); + + b.Property("GroupUserUID") + .HasColumnType("character varying(10)") + .HasColumnName("group_user_uid"); + + b.Property("IsModerator") + .HasColumnType("boolean") + .HasColumnName("is_moderator"); + + b.Property("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("LightlessSyncShared.Models.GroupPairPreferredPermission", b => + { + b.Property("UserUID") + .HasColumnType("character varying(10)") + .HasColumnName("user_uid"); + + b.Property("GroupGID") + .HasColumnType("character varying(20)") + .HasColumnName("group_gid"); + + b.Property("DisableAnimations") + .HasColumnType("boolean") + .HasColumnName("disable_animations"); + + b.Property("DisableSounds") + .HasColumnType("boolean") + .HasColumnName("disable_sounds"); + + b.Property("DisableVFX") + .HasColumnType("boolean") + .HasColumnName("disable_vfx"); + + b.Property("IsPaused") + .HasColumnType("boolean") + .HasColumnName("is_paused"); + + b.HasKey("UserUID", "GroupGID") + .HasName("pk_group_pair_preferred_permissions"); + + b.HasIndex("GroupGID") + .HasDatabaseName("ix_group_pair_preferred_permissions_group_gid"); + + b.HasIndex("UserUID") + .HasDatabaseName("ix_group_pair_preferred_permissions_user_uid"); + + b.ToTable("group_pair_preferred_permissions", (string)null); + }); + + modelBuilder.Entity("LightlessSyncShared.Models.GroupTempInvite", b => + { + b.Property("GroupGID") + .HasColumnType("character varying(20)") + .HasColumnName("group_gid"); + + b.Property("Invite") + .HasMaxLength(64) + .HasColumnType("character varying(64)") + .HasColumnName("invite"); + + b.Property("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("LightlessSyncShared.Models.LodeStoneAuth", b => + { + b.Property("DiscordId") + .ValueGeneratedOnAdd() + .HasColumnType("numeric(20,0)") + .HasColumnName("discord_id"); + + b.Property("HashedLodestoneId") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("hashed_lodestone_id"); + + b.Property("LodestoneAuthString") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("lodestone_auth_string"); + + b.Property("StartedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("started_at"); + + b.Property("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("LightlessSyncShared.Models.User", b => + { + b.Property("UID") + .HasMaxLength(10) + .HasColumnType("character varying(10)") + .HasColumnName("uid"); + + b.Property("Alias") + .HasMaxLength(15) + .HasColumnType("character varying(15)") + .HasColumnName("alias"); + + b.Property("IsAdmin") + .HasColumnType("boolean") + .HasColumnName("is_admin"); + + b.Property("IsModerator") + .HasColumnType("boolean") + .HasColumnName("is_moderator"); + + b.Property("LastLoggedIn") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_logged_in"); + + b.Property("Timestamp") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("bytea") + .HasColumnName("timestamp"); + + b.HasKey("UID") + .HasName("pk_users"); + + b.ToTable("users", (string)null); + }); + + modelBuilder.Entity("LightlessSyncShared.Models.UserDefaultPreferredPermission", b => + { + b.Property("UserUID") + .HasMaxLength(10) + .HasColumnType("character varying(10)") + .HasColumnName("user_uid"); + + b.Property("DisableGroupAnimations") + .HasColumnType("boolean") + .HasColumnName("disable_group_animations"); + + b.Property("DisableGroupSounds") + .HasColumnType("boolean") + .HasColumnName("disable_group_sounds"); + + b.Property("DisableGroupVFX") + .HasColumnType("boolean") + .HasColumnName("disable_group_vfx"); + + b.Property("DisableIndividualAnimations") + .HasColumnType("boolean") + .HasColumnName("disable_individual_animations"); + + b.Property("DisableIndividualSounds") + .HasColumnType("boolean") + .HasColumnName("disable_individual_sounds"); + + b.Property("DisableIndividualVFX") + .HasColumnType("boolean") + .HasColumnName("disable_individual_vfx"); + + b.Property("IndividualIsSticky") + .HasColumnType("boolean") + .HasColumnName("individual_is_sticky"); + + b.HasKey("UserUID") + .HasName("pk_user_default_preferred_permissions"); + + b.HasIndex("UserUID") + .HasDatabaseName("ix_user_default_preferred_permissions_user_uid"); + + b.ToTable("user_default_preferred_permissions", (string)null); + }); + + modelBuilder.Entity("LightlessSyncShared.Models.UserPermissionSet", b => + { + b.Property("UserUID") + .HasColumnType("character varying(10)") + .HasColumnName("user_uid"); + + b.Property("OtherUserUID") + .HasColumnType("character varying(10)") + .HasColumnName("other_user_uid"); + + b.Property("DisableAnimations") + .HasColumnType("boolean") + .HasColumnName("disable_animations"); + + b.Property("DisableSounds") + .HasColumnType("boolean") + .HasColumnName("disable_sounds"); + + b.Property("DisableVFX") + .HasColumnType("boolean") + .HasColumnName("disable_vfx"); + + b.Property("IsPaused") + .HasColumnType("boolean") + .HasColumnName("is_paused"); + + b.Property("Sticky") + .HasColumnType("boolean") + .HasColumnName("sticky"); + + b.HasKey("UserUID", "OtherUserUID") + .HasName("pk_user_permission_sets"); + + b.HasIndex("OtherUserUID") + .HasDatabaseName("ix_user_permission_sets_other_user_uid"); + + b.HasIndex("UserUID") + .HasDatabaseName("ix_user_permission_sets_user_uid"); + + b.HasIndex("UserUID", "OtherUserUID", "IsPaused") + .HasDatabaseName("ix_user_permission_sets_user_uid_other_user_uid_is_paused"); + + b.ToTable("user_permission_sets", (string)null); + }); + + modelBuilder.Entity("LightlessSyncShared.Models.UserProfileData", b => + { + b.Property("UserUID") + .HasColumnType("character varying(10)") + .HasColumnName("user_uid"); + + b.Property("Base64ProfileImage") + .HasColumnType("text") + .HasColumnName("base64profile_image"); + + b.Property("FlaggedForReport") + .HasColumnType("boolean") + .HasColumnName("flagged_for_report"); + + b.Property("IsNSFW") + .HasColumnType("boolean") + .HasColumnName("is_nsfw"); + + b.Property("ProfileDisabled") + .HasColumnType("boolean") + .HasColumnName("profile_disabled"); + + b.Property("UserDescription") + .HasColumnType("text") + .HasColumnName("user_description"); + + b.HasKey("UserUID") + .HasName("pk_user_profile_data"); + + b.ToTable("user_profile_data", (string)null); + }); + + modelBuilder.Entity("LightlessSyncShared.Models.Auth", b => + { + b.HasOne("LightlessSyncShared.Models.User", "PrimaryUser") + .WithMany() + .HasForeignKey("PrimaryUserUID") + .HasConstraintName("fk_auth_users_primary_user_uid"); + + b.HasOne("LightlessSyncShared.Models.User", "User") + .WithMany() + .HasForeignKey("UserUID") + .HasConstraintName("fk_auth_users_user_uid"); + + b.Navigation("PrimaryUser"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LightlessSyncShared.Models.CharaData", b => + { + b.HasOne("LightlessSyncShared.Models.User", "Uploader") + .WithMany() + .HasForeignKey("UploaderUID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_chara_data_users_uploader_uid"); + + b.Navigation("Uploader"); + }); + + modelBuilder.Entity("LightlessSyncShared.Models.CharaDataAllowance", b => + { + b.HasOne("LightlessSyncShared.Models.Group", "AllowedGroup") + .WithMany() + .HasForeignKey("AllowedGroupGID") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_chara_data_allowance_groups_allowed_group_gid"); + + b.HasOne("LightlessSyncShared.Models.User", "AllowedUser") + .WithMany() + .HasForeignKey("AllowedUserUID") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_chara_data_allowance_users_allowed_user_uid"); + + b.HasOne("LightlessSyncShared.Models.CharaData", "Parent") + .WithMany("AllowedIndividiuals") + .HasForeignKey("ParentId", "ParentUploaderUID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_chara_data_allowance_chara_data_parent_id_parent_uploader_u"); + + b.Navigation("AllowedGroup"); + + b.Navigation("AllowedUser"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("LightlessSyncShared.Models.CharaDataFile", b => + { + b.HasOne("LightlessSyncShared.Models.FileCache", "FileCache") + .WithMany() + .HasForeignKey("FileCacheHash") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_chara_data_files_files_file_cache_hash"); + + b.HasOne("LightlessSyncShared.Models.CharaData", "Parent") + .WithMany("Files") + .HasForeignKey("ParentId", "ParentUploaderUID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_chara_data_files_chara_data_parent_id_parent_uploader_uid"); + + b.Navigation("FileCache"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("LightlessSyncShared.Models.CharaDataFileSwap", b => + { + b.HasOne("LightlessSyncShared.Models.CharaData", "Parent") + .WithMany("FileSwaps") + .HasForeignKey("ParentId", "ParentUploaderUID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_chara_data_file_swaps_chara_data_parent_id_parent_uploader_"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("LightlessSyncShared.Models.CharaDataOriginalFile", b => + { + b.HasOne("LightlessSyncShared.Models.CharaData", "Parent") + .WithMany("OriginalFiles") + .HasForeignKey("ParentId", "ParentUploaderUID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_chara_data_orig_files_chara_data_parent_id_parent_uploader_"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("LightlessSyncShared.Models.CharaDataPose", b => + { + b.HasOne("LightlessSyncShared.Models.CharaData", "Parent") + .WithMany("Poses") + .HasForeignKey("ParentId", "ParentUploaderUID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_chara_data_poses_chara_data_parent_id_parent_uploader_uid"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("LightlessSyncShared.Models.ClientPair", b => + { + b.HasOne("LightlessSyncShared.Models.User", "OtherUser") + .WithMany() + .HasForeignKey("OtherUserUID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_client_pairs_users_other_user_uid"); + + b.HasOne("LightlessSyncShared.Models.User", "User") + .WithMany() + .HasForeignKey("UserUID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_client_pairs_users_user_uid"); + + b.Navigation("OtherUser"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LightlessSyncShared.Models.FileCache", b => + { + b.HasOne("LightlessSyncShared.Models.User", "Uploader") + .WithMany() + .HasForeignKey("UploaderUID") + .HasConstraintName("fk_file_caches_users_uploader_uid"); + + b.Navigation("Uploader"); + }); + + modelBuilder.Entity("LightlessSyncShared.Models.Group", b => + { + b.HasOne("LightlessSyncShared.Models.User", "Owner") + .WithMany() + .HasForeignKey("OwnerUID") + .HasConstraintName("fk_groups_users_owner_uid"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("LightlessSyncShared.Models.GroupBan", b => + { + b.HasOne("LightlessSyncShared.Models.User", "BannedBy") + .WithMany() + .HasForeignKey("BannedByUID") + .HasConstraintName("fk_group_bans_users_banned_by_uid"); + + b.HasOne("LightlessSyncShared.Models.User", "BannedUser") + .WithMany() + .HasForeignKey("BannedUserUID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_group_bans_users_banned_user_uid"); + + b.HasOne("LightlessSyncShared.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupGID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_group_bans_groups_group_gid"); + + b.Navigation("BannedBy"); + + b.Navigation("BannedUser"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("LightlessSyncShared.Models.GroupPair", b => + { + b.HasOne("LightlessSyncShared.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupGID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_group_pairs_groups_group_gid"); + + b.HasOne("LightlessSyncShared.Models.User", "GroupUser") + .WithMany() + .HasForeignKey("GroupUserUID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_group_pairs_users_group_user_uid"); + + b.Navigation("Group"); + + b.Navigation("GroupUser"); + }); + + modelBuilder.Entity("LightlessSyncShared.Models.GroupPairPreferredPermission", b => + { + b.HasOne("LightlessSyncShared.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupGID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_group_pair_preferred_permissions_groups_group_gid"); + + b.HasOne("LightlessSyncShared.Models.User", "User") + .WithMany() + .HasForeignKey("UserUID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_group_pair_preferred_permissions_users_user_uid"); + + b.Navigation("Group"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LightlessSyncShared.Models.GroupTempInvite", b => + { + b.HasOne("LightlessSyncShared.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupGID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_group_temp_invites_groups_group_gid"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("LightlessSyncShared.Models.LodeStoneAuth", b => + { + b.HasOne("LightlessSyncShared.Models.User", "User") + .WithMany() + .HasForeignKey("UserUID") + .HasConstraintName("fk_lodestone_auth_users_user_uid"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LightlessSyncShared.Models.UserDefaultPreferredPermission", b => + { + b.HasOne("LightlessSyncShared.Models.User", "User") + .WithMany() + .HasForeignKey("UserUID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_user_default_preferred_permissions_users_user_uid"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LightlessSyncShared.Models.UserPermissionSet", b => + { + b.HasOne("LightlessSyncShared.Models.User", "OtherUser") + .WithMany() + .HasForeignKey("OtherUserUID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_user_permission_sets_users_other_user_uid"); + + b.HasOne("LightlessSyncShared.Models.User", "User") + .WithMany() + .HasForeignKey("UserUID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_user_permission_sets_users_user_uid"); + + b.Navigation("OtherUser"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LightlessSyncShared.Models.UserProfileData", b => + { + b.HasOne("LightlessSyncShared.Models.User", "User") + .WithMany() + .HasForeignKey("UserUID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_user_profile_data_users_user_uid"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LightlessSyncShared.Models.CharaData", b => + { + b.Navigation("AllowedIndividiuals"); + + b.Navigation("FileSwaps"); + + b.Navigation("Files"); + + b.Navigation("OriginalFiles"); + + b.Navigation("Poses"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/LightlessSyncServer/LightlessSyncShared/Migrations/20250905192853_AddBannedUid.cs b/LightlessSyncServer/LightlessSyncShared/Migrations/20250905192853_AddBannedUid.cs new file mode 100644 index 0000000..0467a67 --- /dev/null +++ b/LightlessSyncServer/LightlessSyncShared/Migrations/20250905192853_AddBannedUid.cs @@ -0,0 +1,28 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace LightlessSyncServer.Migrations +{ + /// + public partial class AddBannedUid : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "banned_uid", + table: "banned_users", + type: "text", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "banned_uid", + table: "banned_users"); + } + } +} diff --git a/LightlessSyncServer/LightlessSyncShared/Migrations/MareDbContextModelSnapshot.cs b/LightlessSyncServer/LightlessSyncShared/Migrations/LightlessDbContextModelSnapshot.cs similarity index 99% rename from LightlessSyncServer/LightlessSyncShared/Migrations/MareDbContextModelSnapshot.cs rename to LightlessSyncServer/LightlessSyncShared/Migrations/LightlessDbContextModelSnapshot.cs index f5f0cdc..e2ce4c6 100644 --- a/LightlessSyncServer/LightlessSyncShared/Migrations/MareDbContextModelSnapshot.cs +++ b/LightlessSyncServer/LightlessSyncShared/Migrations/LightlessDbContextModelSnapshot.cs @@ -64,6 +64,10 @@ namespace LightlessSyncServer.Migrations .HasColumnType("character varying(100)") .HasColumnName("character_identification"); + b.Property("BannedUid") + .HasColumnType("text") + .HasColumnName("banned_uid"); + b.Property("Reason") .HasColumnType("text") .HasColumnName("reason"); diff --git a/LightlessSyncServer/LightlessSyncShared/Models/Banned.cs b/LightlessSyncServer/LightlessSyncShared/Models/Banned.cs index 25886e0..4071f56 100644 --- a/LightlessSyncServer/LightlessSyncShared/Models/Banned.cs +++ b/LightlessSyncServer/LightlessSyncShared/Models/Banned.cs @@ -7,6 +7,7 @@ public class Banned [Key] [MaxLength(100)] public string CharacterIdentification { get; set; } + public string BannedUid { get; set; } public string Reason { get; set; } [Timestamp] public byte[] Timestamp { get; set; }