From 81261fae49bf68d1d783077cd8b0b9173fd56065 Mon Sep 17 00:00:00 2001 From: defnotken Date: Tue, 16 Sep 2025 09:52:15 -0500 Subject: [PATCH 01/17] Database changes for syncshell changes --- .../LightlessSyncShared/Data/MareDbContext.cs | 9 + ...45052_AddGroupProfilesAndDates.Designer.cs | 1149 +++++++++++++++++ ...20250916145052_AddGroupProfilesAndDates.cs | 80 ++ .../LightlessDbContextModelSnapshot.cs | 51 + .../LightlessSyncShared/Models/Group.cs | 1 + .../LightlessSyncShared/Models/GroupPair.cs | 2 + .../Models/GroupProfile.cs | 15 + 7 files changed, 1307 insertions(+) create mode 100644 LightlessSyncServer/LightlessSyncShared/Migrations/20250916145052_AddGroupProfilesAndDates.Designer.cs create mode 100644 LightlessSyncServer/LightlessSyncShared/Migrations/20250916145052_AddGroupProfilesAndDates.cs create mode 100644 LightlessSyncServer/LightlessSyncShared/Models/GroupProfile.cs diff --git a/LightlessSyncServer/LightlessSyncShared/Data/MareDbContext.cs b/LightlessSyncServer/LightlessSyncShared/Data/MareDbContext.cs index dc7b17f..b9ece6c 100644 --- a/LightlessSyncServer/LightlessSyncShared/Data/MareDbContext.cs +++ b/LightlessSyncServer/LightlessSyncShared/Data/MareDbContext.cs @@ -53,6 +53,7 @@ public class LightlessDbContext : DbContext public DbSet CharaDataOriginalFiles { get; set; } public DbSet CharaDataPoses { get; set; } public DbSet CharaDataAllowances { get; set; } + public DbSet GroupProfiles { get; set; } protected override void OnModelCreating(ModelBuilder mb) { @@ -78,6 +79,14 @@ public class LightlessDbContext : DbContext mb.Entity().HasKey(u => new { u.GroupGID, u.BannedUserUID }); mb.Entity().HasIndex(c => c.BannedUserUID); mb.Entity().HasIndex(c => c.GroupGID); + mb.Entity().ToTable("group_profiles"); + mb.Entity().HasKey(u => u.GroupGID); + mb.Entity().HasIndex(c => c.GroupGID); + mb.Entity() + .HasOne(gp => gp.Group) + .WithMany() + .HasForeignKey(gp => gp.GroupGID) + .OnDelete(DeleteBehavior.Cascade); mb.Entity().ToTable("group_temp_invites"); mb.Entity().HasKey(u => new { u.GroupGID, u.Invite }); mb.Entity().HasIndex(c => c.GroupGID); diff --git a/LightlessSyncServer/LightlessSyncShared/Migrations/20250916145052_AddGroupProfilesAndDates.Designer.cs b/LightlessSyncServer/LightlessSyncShared/Migrations/20250916145052_AddGroupProfilesAndDates.Designer.cs new file mode 100644 index 0000000..7fc7446 --- /dev/null +++ b/LightlessSyncServer/LightlessSyncShared/Migrations/20250916145052_AddGroupProfilesAndDates.Designer.cs @@ -0,0 +1,1149 @@ +// +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("20250916145052_AddGroupProfilesAndDates")] + partial class AddGroupProfilesAndDates + { + /// + 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("CreatedDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_date"); + + 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("FromFinder") + .HasColumnType("boolean") + .HasColumnName("from_finder"); + + b.Property("IsModerator") + .HasColumnType("boolean") + .HasColumnName("is_moderator"); + + b.Property("IsPinned") + .HasColumnType("boolean") + .HasColumnName("is_pinned"); + + b.Property("JoinedGroupOn") + .HasColumnType("timestamp with time zone") + .HasColumnName("joined_group_on"); + + 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.GroupProfile", b => + { + b.Property("GroupGID") + .HasColumnType("character varying(20)") + .HasColumnName("group_gid"); + + b.Property("Base64GroupProfileImage") + .HasColumnType("text") + .HasColumnName("base64group_profile_image"); + + b.Property("Description") + .HasColumnType("text") + .HasColumnName("description"); + + b.Property("Tags") + .HasColumnType("text") + .HasColumnName("tags"); + + b.HasKey("GroupGID") + .HasName("pk_group_profiles"); + + b.HasIndex("GroupGID") + .HasDatabaseName("ix_group_profiles_group_gid"); + + b.ToTable("group_profiles", (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.GroupProfile", b => + { + b.HasOne("LightlessSyncShared.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupGID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_group_profiles_groups_group_gid"); + + b.Navigation("Group"); + }); + + 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/20250916145052_AddGroupProfilesAndDates.cs b/LightlessSyncServer/LightlessSyncShared/Migrations/20250916145052_AddGroupProfilesAndDates.cs new file mode 100644 index 0000000..00d7d92 --- /dev/null +++ b/LightlessSyncServer/LightlessSyncShared/Migrations/20250916145052_AddGroupProfilesAndDates.cs @@ -0,0 +1,80 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace LightlessSyncServer.Migrations +{ + /// + public partial class AddGroupProfilesAndDates : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "created_date", + table: "groups", + type: "timestamp with time zone", + nullable: false, + defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)); + + migrationBuilder.AddColumn( + name: "from_finder", + table: "group_pairs", + type: "boolean", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "joined_group_on", + table: "group_pairs", + type: "timestamp with time zone", + nullable: false, + defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)); + + migrationBuilder.CreateTable( + name: "group_profiles", + columns: table => new + { + group_gid = table.Column(type: "character varying(20)", nullable: false), + description = table.Column(type: "text", nullable: true), + tags = table.Column(type: "text", nullable: true), + base64group_profile_image = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_group_profiles", x => x.group_gid); + table.ForeignKey( + name: "fk_group_profiles_groups_group_gid", + column: x => x.group_gid, + principalTable: "groups", + principalColumn: "gid", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "ix_group_profiles_group_gid", + table: "group_profiles", + column: "group_gid"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "group_profiles"); + + migrationBuilder.DropColumn( + name: "created_date", + table: "groups"); + + migrationBuilder.DropColumn( + name: "from_finder", + table: "group_pairs"); + + migrationBuilder.DropColumn( + name: "joined_group_on", + table: "group_pairs"); + } + } +} diff --git a/LightlessSyncServer/LightlessSyncShared/Migrations/LightlessDbContextModelSnapshot.cs b/LightlessSyncServer/LightlessSyncShared/Migrations/LightlessDbContextModelSnapshot.cs index e2ce4c6..cfc8535 100644 --- a/LightlessSyncServer/LightlessSyncShared/Migrations/LightlessDbContextModelSnapshot.cs +++ b/LightlessSyncServer/LightlessSyncShared/Migrations/LightlessDbContextModelSnapshot.cs @@ -430,6 +430,10 @@ namespace LightlessSyncServer.Migrations .HasColumnType("character varying(50)") .HasColumnName("alias"); + b.Property("CreatedDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_date"); + b.Property("HashedPassword") .HasColumnType("text") .HasColumnName("hashed_password"); @@ -510,6 +514,10 @@ namespace LightlessSyncServer.Migrations .HasColumnType("character varying(10)") .HasColumnName("group_user_uid"); + b.Property("FromFinder") + .HasColumnType("boolean") + .HasColumnName("from_finder"); + b.Property("IsModerator") .HasColumnType("boolean") .HasColumnName("is_moderator"); @@ -518,6 +526,10 @@ namespace LightlessSyncServer.Migrations .HasColumnType("boolean") .HasColumnName("is_pinned"); + b.Property("JoinedGroupOn") + .HasColumnType("timestamp with time zone") + .HasColumnName("joined_group_on"); + b.HasKey("GroupGID", "GroupUserUID") .HasName("pk_group_pairs"); @@ -568,6 +580,33 @@ namespace LightlessSyncServer.Migrations b.ToTable("group_pair_preferred_permissions", (string)null); }); + modelBuilder.Entity("LightlessSyncShared.Models.GroupProfile", b => + { + b.Property("GroupGID") + .HasColumnType("character varying(20)") + .HasColumnName("group_gid"); + + b.Property("Base64GroupProfileImage") + .HasColumnType("text") + .HasColumnName("base64group_profile_image"); + + b.Property("Description") + .HasColumnType("text") + .HasColumnName("description"); + + b.Property("Tags") + .HasColumnType("text") + .HasColumnName("tags"); + + b.HasKey("GroupGID") + .HasName("pk_group_profiles"); + + b.HasIndex("GroupGID") + .HasDatabaseName("ix_group_profiles_group_gid"); + + b.ToTable("group_profiles", (string)null); + }); + modelBuilder.Entity("LightlessSyncShared.Models.GroupTempInvite", b => { b.Property("GroupGID") @@ -1010,6 +1049,18 @@ namespace LightlessSyncServer.Migrations b.Navigation("User"); }); + modelBuilder.Entity("LightlessSyncShared.Models.GroupProfile", b => + { + b.HasOne("LightlessSyncShared.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupGID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_group_profiles_groups_group_gid"); + + b.Navigation("Group"); + }); + modelBuilder.Entity("LightlessSyncShared.Models.GroupTempInvite", b => { b.HasOne("LightlessSyncShared.Models.Group", "Group") diff --git a/LightlessSyncServer/LightlessSyncShared/Models/Group.cs b/LightlessSyncServer/LightlessSyncShared/Models/Group.cs index 67de63d..2188a5b 100644 --- a/LightlessSyncServer/LightlessSyncShared/Models/Group.cs +++ b/LightlessSyncServer/LightlessSyncShared/Models/Group.cs @@ -16,4 +16,5 @@ public class Group public bool PreferDisableSounds { get; set; } public bool PreferDisableAnimations { get; set; } public bool PreferDisableVFX { get; set; } + public DateTime CreatedDate { get; set; } = DateTime.UtcNow; } diff --git a/LightlessSyncServer/LightlessSyncShared/Models/GroupPair.cs b/LightlessSyncServer/LightlessSyncShared/Models/GroupPair.cs index bb5824e..15e0e7f 100644 --- a/LightlessSyncServer/LightlessSyncShared/Models/GroupPair.cs +++ b/LightlessSyncServer/LightlessSyncShared/Models/GroupPair.cs @@ -8,4 +8,6 @@ public class GroupPair public User GroupUser { get; set; } public bool IsPinned { get; set; } public bool IsModerator { get; set; } + public bool FromFinder { get; set; } = false; + public DateTime JoinedGroupOn { get; set; } } diff --git a/LightlessSyncServer/LightlessSyncShared/Models/GroupProfile.cs b/LightlessSyncServer/LightlessSyncShared/Models/GroupProfile.cs new file mode 100644 index 0000000..ea750d8 --- /dev/null +++ b/LightlessSyncServer/LightlessSyncShared/Models/GroupProfile.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LightlessSyncShared.Models; +public class GroupProfile +{ + public string GroupGID { get; set; } + public Group Group { get; set; } + public string Description { get; set; } + public string Tags { get; set; } + public string Base64GroupProfileImage { get; set; } +} From 0df7ee424d820e208c34c80a01d685a21ec3182a Mon Sep 17 00:00:00 2001 From: defnotken Date: Tue, 16 Sep 2025 15:03:15 -0500 Subject: [PATCH 02/17] db changes --- .../LightlessSyncShared/Data/MareDbContext.cs | 3 +++ ...> 20250916200240_AddGroupProfilesAndDates.Designer.cs} | 8 +++++--- ...ates.cs => 20250916200240_AddGroupProfilesAndDates.cs} | 5 ++--- .../Migrations/LightlessDbContextModelSnapshot.cs | 6 ++++-- .../LightlessSyncShared/Models/GroupPair.cs | 2 +- 5 files changed, 15 insertions(+), 9 deletions(-) rename LightlessSyncServer/LightlessSyncShared/Migrations/{20250916145052_AddGroupProfilesAndDates.Designer.cs => 20250916200240_AddGroupProfilesAndDates.Designer.cs} (99%) rename LightlessSyncServer/LightlessSyncShared/Migrations/{20250916145052_AddGroupProfilesAndDates.cs => 20250916200240_AddGroupProfilesAndDates.cs} (92%) diff --git a/LightlessSyncServer/LightlessSyncShared/Data/MareDbContext.cs b/LightlessSyncServer/LightlessSyncShared/Data/MareDbContext.cs index b9ece6c..4f38ad8 100644 --- a/LightlessSyncServer/LightlessSyncShared/Data/MareDbContext.cs +++ b/LightlessSyncServer/LightlessSyncShared/Data/MareDbContext.cs @@ -71,6 +71,9 @@ public class LightlessDbContext : DbContext mb.Entity().ToTable("banned_registrations"); mb.Entity().ToTable("groups"); mb.Entity().HasIndex(c => c.OwnerUID); + mb.Entity() + .Property(g => g.CreatedDate) + .HasDefaultValueSql("CURRENT_TIMESTAMP"); mb.Entity().ToTable("group_pairs"); mb.Entity().HasKey(u => new { u.GroupGID, u.GroupUserUID }); mb.Entity().HasIndex(c => c.GroupUserUID); diff --git a/LightlessSyncServer/LightlessSyncShared/Migrations/20250916145052_AddGroupProfilesAndDates.Designer.cs b/LightlessSyncServer/LightlessSyncShared/Migrations/20250916200240_AddGroupProfilesAndDates.Designer.cs similarity index 99% rename from LightlessSyncServer/LightlessSyncShared/Migrations/20250916145052_AddGroupProfilesAndDates.Designer.cs rename to LightlessSyncServer/LightlessSyncShared/Migrations/20250916200240_AddGroupProfilesAndDates.Designer.cs index 7fc7446..0ad25ec 100644 --- a/LightlessSyncServer/LightlessSyncShared/Migrations/20250916145052_AddGroupProfilesAndDates.Designer.cs +++ b/LightlessSyncServer/LightlessSyncShared/Migrations/20250916200240_AddGroupProfilesAndDates.Designer.cs @@ -12,7 +12,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; namespace LightlessSyncServer.Migrations { [DbContext(typeof(LightlessDbContext))] - [Migration("20250916145052_AddGroupProfilesAndDates")] + [Migration("20250916200240_AddGroupProfilesAndDates")] partial class AddGroupProfilesAndDates { /// @@ -434,8 +434,10 @@ namespace LightlessSyncServer.Migrations .HasColumnName("alias"); b.Property("CreatedDate") + .ValueGeneratedOnAdd() .HasColumnType("timestamp with time zone") - .HasColumnName("created_date"); + .HasColumnName("created_date") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); b.Property("HashedPassword") .HasColumnType("text") @@ -529,7 +531,7 @@ namespace LightlessSyncServer.Migrations .HasColumnType("boolean") .HasColumnName("is_pinned"); - b.Property("JoinedGroupOn") + b.Property("JoinedGroupOn") .HasColumnType("timestamp with time zone") .HasColumnName("joined_group_on"); diff --git a/LightlessSyncServer/LightlessSyncShared/Migrations/20250916145052_AddGroupProfilesAndDates.cs b/LightlessSyncServer/LightlessSyncShared/Migrations/20250916200240_AddGroupProfilesAndDates.cs similarity index 92% rename from LightlessSyncServer/LightlessSyncShared/Migrations/20250916145052_AddGroupProfilesAndDates.cs rename to LightlessSyncServer/LightlessSyncShared/Migrations/20250916200240_AddGroupProfilesAndDates.cs index 00d7d92..523ceee 100644 --- a/LightlessSyncServer/LightlessSyncShared/Migrations/20250916145052_AddGroupProfilesAndDates.cs +++ b/LightlessSyncServer/LightlessSyncShared/Migrations/20250916200240_AddGroupProfilesAndDates.cs @@ -16,7 +16,7 @@ namespace LightlessSyncServer.Migrations table: "groups", type: "timestamp with time zone", nullable: false, - defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)); + defaultValueSql: "CURRENT_TIMESTAMP"); migrationBuilder.AddColumn( name: "from_finder", @@ -29,8 +29,7 @@ namespace LightlessSyncServer.Migrations name: "joined_group_on", table: "group_pairs", type: "timestamp with time zone", - nullable: false, - defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)); + nullable: true); migrationBuilder.CreateTable( name: "group_profiles", diff --git a/LightlessSyncServer/LightlessSyncShared/Migrations/LightlessDbContextModelSnapshot.cs b/LightlessSyncServer/LightlessSyncShared/Migrations/LightlessDbContextModelSnapshot.cs index cfc8535..391143b 100644 --- a/LightlessSyncServer/LightlessSyncShared/Migrations/LightlessDbContextModelSnapshot.cs +++ b/LightlessSyncServer/LightlessSyncShared/Migrations/LightlessDbContextModelSnapshot.cs @@ -431,8 +431,10 @@ namespace LightlessSyncServer.Migrations .HasColumnName("alias"); b.Property("CreatedDate") + .ValueGeneratedOnAdd() .HasColumnType("timestamp with time zone") - .HasColumnName("created_date"); + .HasColumnName("created_date") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); b.Property("HashedPassword") .HasColumnType("text") @@ -526,7 +528,7 @@ namespace LightlessSyncServer.Migrations .HasColumnType("boolean") .HasColumnName("is_pinned"); - b.Property("JoinedGroupOn") + b.Property("JoinedGroupOn") .HasColumnType("timestamp with time zone") .HasColumnName("joined_group_on"); diff --git a/LightlessSyncServer/LightlessSyncShared/Models/GroupPair.cs b/LightlessSyncServer/LightlessSyncShared/Models/GroupPair.cs index 15e0e7f..f04db3f 100644 --- a/LightlessSyncServer/LightlessSyncShared/Models/GroupPair.cs +++ b/LightlessSyncServer/LightlessSyncShared/Models/GroupPair.cs @@ -9,5 +9,5 @@ public class GroupPair public bool IsPinned { get; set; } public bool IsModerator { get; set; } public bool FromFinder { get; set; } = false; - public DateTime JoinedGroupOn { get; set; } + public DateTime? JoinedGroupOn { get; set; } } From f5b03846fee280cc40c5dc4a2e2b856d9c1b7c0c Mon Sep 17 00:00:00 2001 From: CakeAndBanana Date: Wed, 17 Sep 2025 02:07:46 +0200 Subject: [PATCH 03/17] Added changes for the profiles to be returned and be able to be changed. --- .../Hubs/MareHub.Groups.cs | 121 ++++++++++++------ .../LightlessSyncServer/Utils/Extensions.cs | 2 +- .../LightlessSyncShared/Models/Group.cs | 1 + .../LightlessSyncShared/Models/GroupPair.cs | 1 + .../Models/GroupProfile.cs | 8 +- 5 files changed, 86 insertions(+), 47 deletions(-) diff --git a/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs b/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs index f9895ff..f0468dd 100644 --- a/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs +++ b/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs @@ -57,7 +57,7 @@ public partial class LightlessHub group.PreferDisableAnimations = dto.Permissions.HasFlag(GroupPermissions.PreferDisableAnimations); group.PreferDisableVFX = dto.Permissions.HasFlag(GroupPermissions.PreferDisableVFX); - await DbContext.SaveChangesAsync().ConfigureAwait(false); + await DbContext.SaveChangesAsync(_contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); var groupPairs = DbContext.GroupPairs.Where(p => p.GroupGID == dto.Group.GID).Select(p => p.GroupUserUID).ToList(); await Clients.Users(groupPairs).Client_GroupChangePermissions(new GroupPermissionDto(dto.Group, dto.Permissions)).ConfigureAwait(false); @@ -151,15 +151,15 @@ public partial class LightlessHub public async Task GroupCreate() { _logger.LogCallInfo(); - var existingGroupsByUser = await DbContext.Groups.CountAsync(u => u.OwnerUID == UserUID).ConfigureAwait(false); - var existingJoinedGroups = await DbContext.GroupPairs.CountAsync(u => u.GroupUserUID == UserUID).ConfigureAwait(false); + var existingGroupsByUser = await DbContext.Groups.CountAsync(u => u.OwnerUID == UserUID, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); + var existingJoinedGroups = await DbContext.GroupPairs.CountAsync(u => u.GroupUserUID == UserUID, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); if (existingGroupsByUser >= _maxExistingGroupsByUser || existingJoinedGroups >= _maxJoinedGroupsByUser) { throw new System.Exception($"Max groups for user is {_maxExistingGroupsByUser}, max joined groups is {_maxJoinedGroupsByUser}."); } var gid = StringUtils.GenerateRandomString(12); - while (await DbContext.Groups.AnyAsync(g => g.GID == "MSS-" + gid).ConfigureAwait(false)) + while (await DbContext.Groups.AnyAsync(g => g.GID == "MSS-" + gid, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false)) { gid = StringUtils.GenerateRandomString(12); } @@ -168,8 +168,9 @@ public partial class LightlessHub var passwd = StringUtils.GenerateRandomString(16); using var sha = SHA256.Create(); var hashedPw = StringUtils.Sha256String(passwd); + var currentTime = DateTime.UtcNow; - UserDefaultPreferredPermission defaultPermissions = await DbContext.UserDefaultPreferredPermissions.SingleAsync(u => u.UserUID == UserUID).ConfigureAwait(false); + UserDefaultPreferredPermission defaultPermissions = await DbContext.UserDefaultPreferredPermissions.SingleAsync(u => u.UserUID == UserUID, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); Group newGroup = new() { @@ -179,7 +180,8 @@ public partial class LightlessHub OwnerUID = UserUID, PreferDisableAnimations = defaultPermissions.DisableGroupAnimations, PreferDisableSounds = defaultPermissions.DisableGroupSounds, - PreferDisableVFX = defaultPermissions.DisableGroupVFX + PreferDisableVFX = defaultPermissions.DisableGroupVFX, + CreatedDate = currentTime, }; GroupPair initialPair = new() @@ -187,6 +189,7 @@ public partial class LightlessHub GroupGID = newGroup.GID, GroupUserUID = UserUID, IsPinned = true, + JoinedGroupOn = currentTime, }; GroupPairPreferredPermission initialPrefPermissions = new() @@ -195,18 +198,18 @@ public partial class LightlessHub GroupGID = newGroup.GID, DisableSounds = defaultPermissions.DisableGroupSounds, DisableAnimations = defaultPermissions.DisableGroupAnimations, - DisableVFX = defaultPermissions.DisableGroupAnimations + DisableVFX = defaultPermissions.DisableGroupAnimations, }; - await DbContext.Groups.AddAsync(newGroup).ConfigureAwait(false); - await DbContext.GroupPairs.AddAsync(initialPair).ConfigureAwait(false); - await DbContext.GroupPairPreferredPermissions.AddAsync(initialPrefPermissions).ConfigureAwait(false); - await DbContext.SaveChangesAsync().ConfigureAwait(false); + await DbContext.Groups.AddAsync(newGroup, _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); + await DbContext.GroupPairs.AddAsync(initialPair, _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); + await DbContext.GroupPairPreferredPermissions.AddAsync(initialPrefPermissions, _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); + await DbContext.SaveChangesAsync(_contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); - var self = await DbContext.Users.SingleAsync(u => u.UID == UserUID).ConfigureAwait(false); + var self = await DbContext.Users.SingleAsync(u => u.UID == UserUID, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); await Clients.User(UserUID).Client_GroupSendFullInfo(new GroupFullInfoDto(newGroup.ToGroupData(), self.ToUserData(), - newGroup.ToEnum(), initialPrefPermissions.ToEnum(), initialPair.ToEnum(), new(StringComparer.Ordinal))) + newGroup.ToEnum(), initialPrefPermissions.ToEnum(), initialPair.ToEnum(), initialPair.JoinedGroupOn, new(StringComparer.Ordinal))) .ConfigureAwait(false); _logger.LogCallInfo(LightlessHubLogger.Args(gid)); @@ -262,10 +265,10 @@ public partial class LightlessHub _logger.LogCallInfo(LightlessHubLogger.Args(dto, "Success")); - var groupPairs = await DbContext.GroupPairs.Where(p => p.GroupGID == dto.Group.GID).ToListAsync().ConfigureAwait(false); + var groupPairs = await DbContext.GroupPairs.Where(p => p.GroupGID == dto.Group.GID).ToListAsync(cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); DbContext.RemoveRange(groupPairs); DbContext.Remove(group); - await DbContext.SaveChangesAsync().ConfigureAwait(false); + await DbContext.SaveChangesAsync(_contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); await Clients.Users(groupPairs.Select(g => g.GroupUserUID)).Client_GroupDelete(new GroupDto(group.ToGroupData())).ConfigureAwait(false); @@ -278,9 +281,9 @@ public partial class LightlessHub _logger.LogCallInfo(LightlessHubLogger.Args(dto)); var (userHasRights, group) = await TryValidateGroupModeratorOrOwner(dto.GID).ConfigureAwait(false); - if (!userHasRights) return new List(); + if (!userHasRights) return []; - var banEntries = await DbContext.GroupBans.Include(b => b.BannedUser).Where(g => g.GroupGID == dto.Group.GID).AsNoTracking().ToListAsync().ConfigureAwait(false); + var banEntries = await DbContext.GroupBans.Include(b => b.BannedUser).Where(g => g.GroupGID == dto.Group.GID).AsNoTracking().ToListAsync(cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); List bannedGroupUsers = banEntries.Select(b => new BannedGroupUserDto(group.ToGroupData(), b.BannedUser.ToUserData(), b.BannedReason, b.BannedOn, @@ -298,14 +301,14 @@ public partial class LightlessHub _logger.LogCallInfo(LightlessHubLogger.Args(dto)); - var group = await DbContext.Groups.Include(g => g.Owner).AsNoTracking().SingleOrDefaultAsync(g => g.GID == aliasOrGid || g.Alias == aliasOrGid).ConfigureAwait(false); + var group = await DbContext.Groups.Include(g => g.Owner).AsNoTracking().SingleOrDefaultAsync(g => g.GID == aliasOrGid || g.Alias == aliasOrGid, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); var groupGid = group?.GID ?? string.Empty; - var existingPair = await DbContext.GroupPairs.AsNoTracking().SingleOrDefaultAsync(g => g.GroupGID == groupGid && g.GroupUserUID == UserUID).ConfigureAwait(false); + var existingPair = await DbContext.GroupPairs.AsNoTracking().SingleOrDefaultAsync(g => g.GroupGID == groupGid && g.GroupUserUID == UserUID, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); var hashedPw = StringUtils.Sha256String(dto.Password); - var existingUserCount = await DbContext.GroupPairs.AsNoTracking().CountAsync(g => g.GroupGID == groupGid).ConfigureAwait(false); - var joinedGroups = await DbContext.GroupPairs.CountAsync(g => g.GroupUserUID == UserUID).ConfigureAwait(false); - var isBanned = await DbContext.GroupBans.AnyAsync(g => g.GroupGID == groupGid && g.BannedUserUID == UserUID).ConfigureAwait(false); - var oneTimeInvite = await DbContext.GroupTempInvites.SingleOrDefaultAsync(g => g.GroupGID == groupGid && g.Invite == hashedPw).ConfigureAwait(false); + var existingUserCount = await DbContext.GroupPairs.AsNoTracking().CountAsync(g => g.GroupGID == groupGid, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); + var joinedGroups = await DbContext.GroupPairs.CountAsync(g => g.GroupUserUID == UserUID, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); + var isBanned = await DbContext.GroupBans.AnyAsync(g => g.GroupGID == groupGid && g.BannedUserUID == UserUID, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); + var oneTimeInvite = await DbContext.GroupTempInvites.SingleOrDefaultAsync(g => g.GroupGID == groupGid && g.Invite == hashedPw, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); if (group == null || (!string.Equals(group.HashedPassword, hashedPw, StringComparison.Ordinal) && oneTimeInvite == null) @@ -357,6 +360,7 @@ public partial class LightlessHub { GroupGID = group.GID, GroupUserUID = UserUID, + JoinedGroupOn = DateTime.UtcNow, }; var preferredPermissions = await DbContext.GroupPairPreferredPermissions.SingleOrDefaultAsync(u => u.UserUID == UserUID && u.GroupGID == group.GID).ConfigureAwait(false); @@ -369,7 +373,7 @@ public partial class LightlessHub DisableSounds = dto.GroupUserPreferredPermissions.IsDisableSounds(), DisableVFX = dto.GroupUserPreferredPermissions.IsDisableVFX(), DisableAnimations = dto.GroupUserPreferredPermissions.IsDisableAnimations(), - IsPaused = false + IsPaused = false, }; DbContext.Add(newPerms); @@ -384,15 +388,15 @@ public partial class LightlessHub DbContext.Update(preferredPermissions); } - await DbContext.GroupPairs.AddAsync(newPair).ConfigureAwait(false); + await DbContext.GroupPairs.AddAsync(newPair, _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); _logger.LogCallInfo(LightlessHubLogger.Args(aliasOrGid, "Success")); - await DbContext.SaveChangesAsync().ConfigureAwait(false); + await DbContext.SaveChangesAsync(_contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); - var groupInfos = await DbContext.GroupPairs.Where(u => u.GroupGID == group.GID && (u.IsPinned || u.IsModerator)).ToListAsync().ConfigureAwait(false); + var groupInfos = await DbContext.GroupPairs.Where(u => u.GroupGID == group.GID && (u.IsPinned || u.IsModerator)).ToListAsync(cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); await Clients.User(UserUID).Client_GroupSendFullInfo(new GroupFullInfoDto(group.ToGroupData(), group.Owner.ToUserData(), - group.ToEnum(), preferredPermissions.ToEnum(), newPair.ToEnum(), + group.ToEnum(), preferredPermissions.ToEnum(), newPair.ToEnum(), newPair.JoinedGroupOn, groupInfos.ToDictionary(u => u.GroupUserUID, u => u.ToEnum(), StringComparer.Ordinal))).ConfigureAwait(false); var self = DbContext.Users.Single(u => u.UID == UserUID); @@ -518,7 +522,7 @@ public partial class LightlessHub } } - await DbContext.SaveChangesAsync().ConfigureAwait(false); + await DbContext.SaveChangesAsync(_contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); return true; } @@ -541,8 +545,8 @@ public partial class LightlessHub .Where(g => g.GroupGID == dto.Group.GID) .ToListAsync().ConfigureAwait(false); var usersToPrune = allGroupUsers.Where(p => !p.IsPinned && !p.IsModerator - && p.GroupUserUID != UserUID - && p.Group.OwnerUID != p.GroupUserUID + && !string.Equals(p.GroupUserUID, UserUID, StringComparison.Ordinal) + && !string.Equals(p.Group.OwnerUID, p.GroupUserUID, StringComparison.Ordinal) && p.GroupUser.LastLoggedIn.AddDays(days) < DateTime.UtcNow); if (!execute) return usersToPrune.Count(); @@ -600,6 +604,45 @@ public partial class LightlessHub } } + [Authorize(Policy = "Identified")] + public async Task GroupSetProfile(GroupProfileDto dto) + { + _logger.LogCallInfo(LightlessHubLogger.Args(dto)); + + if (dto.Group == null) return; + + var (hasRights, group) = await TryValidateGroupModeratorOrOwner(dto.Group.GID).ConfigureAwait(false); + if (!hasRights) return; + + var groupProfileDb = await DbContext.GroupProfiles + .FirstOrDefaultAsync(g => g.GroupGID == dto.Group.GID, + _contextAccessor.HttpContext.RequestAborted) + .ConfigureAwait(false); + + if (groupProfileDb != null) + { + groupProfileDb.Description = dto.Description; + groupProfileDb.Tags = dto.Tags; + groupProfileDb.Base64GroupProfileImage = dto.PictureBase64; + } + else + { + var groupProfile = new GroupProfile + { + GroupGID = dto.Group.GID, + Description = dto.Description, + Tags = dto.Tags, + Base64GroupProfileImage = dto.PictureBase64, + }; + + await DbContext.GroupProfiles.AddAsync(groupProfile, + _contextAccessor.HttpContext.RequestAborted) + .ConfigureAwait(false); + } + + await DbContext.SaveChangesAsync(_contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); + } + [Authorize(Policy = "Identified")] public async Task GroupSetUserInfo(GroupPairUserInfoDto dto) { @@ -629,9 +672,9 @@ public partial class LightlessHub userPair.IsModerator = false; } - await DbContext.SaveChangesAsync().ConfigureAwait(false); + await DbContext.SaveChangesAsync(_contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); - var groupPairs = await DbContext.GroupPairs.AsNoTracking().Where(p => p.GroupGID == dto.Group.GID).Select(p => p.GroupUserUID).ToListAsync().ConfigureAwait(false); + var groupPairs = await DbContext.GroupPairs.AsNoTracking().Where(p => p.GroupGID == dto.Group.GID).Select(p => p.GroupUserUID).ToListAsync(cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); await Clients.Users(groupPairs).Client_GroupPairChangeUserInfo(new GroupPairUserInfoDto(dto.Group, dto.User, userPair.ToEnum())).ConfigureAwait(false); } @@ -640,15 +683,15 @@ public partial class LightlessHub { _logger.LogCallInfo(); - var groups = await DbContext.GroupPairs.Include(g => g.Group).Include(g => g.Group.Owner).Where(g => g.GroupUserUID == UserUID).AsNoTracking().ToListAsync().ConfigureAwait(false); - var preferredPermissions = (await DbContext.GroupPairPreferredPermissions.Where(u => u.UserUID == UserUID).ToListAsync().ConfigureAwait(false)) + var groups = await DbContext.GroupPairs.Include(g => g.Group).Include(g => g.Group.Owner).Where(g => g.GroupUserUID == UserUID).AsNoTracking().ToListAsync(cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); + var preferredPermissions = (await DbContext.GroupPairPreferredPermissions.Where(u => u.UserUID == UserUID).ToListAsync(cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false)) .Where(u => groups.Exists(k => string.Equals(k.GroupGID, u.GroupGID, StringComparison.Ordinal))) .ToDictionary(u => groups.First(f => string.Equals(f.GroupGID, u.GroupGID, StringComparison.Ordinal)), u => u); var groupInfos = await DbContext.GroupPairs.Where(u => groups.Select(g => g.GroupGID).Contains(u.GroupGID) && (u.IsPinned || u.IsModerator)) - .ToListAsync().ConfigureAwait(false); + .ToListAsync(cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); return preferredPermissions.Select(g => new GroupFullInfoDto(g.Key.Group.ToGroupData(), g.Key.Group.Owner.ToUserData(), - g.Key.Group.ToEnum(), g.Value.ToEnum(), g.Key.ToEnum(), + g.Key.Group.ToEnum(), g.Value.ToEnum(), g.Key.ToEnum(), g.Key.JoinedGroupOn, groupInfos.Where(i => string.Equals(i.GroupGID, g.Key.GroupGID, StringComparison.Ordinal)) .ToDictionary(i => i.GroupUserUID, i => i.ToEnum(), StringComparer.Ordinal))).ToList(); } @@ -661,11 +704,11 @@ public partial class LightlessHub var (userHasRights, _) = await TryValidateGroupModeratorOrOwner(dto.Group.GID).ConfigureAwait(false); if (!userHasRights) return; - var banEntry = await DbContext.GroupBans.SingleOrDefaultAsync(g => g.GroupGID == dto.Group.GID && g.BannedUserUID == dto.User.UID).ConfigureAwait(false); + var banEntry = await DbContext.GroupBans.SingleOrDefaultAsync(g => g.GroupGID == dto.Group.GID && g.BannedUserUID == dto.User.UID, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); if (banEntry == null) return; DbContext.Remove(banEntry); - await DbContext.SaveChangesAsync().ConfigureAwait(false); + await DbContext.SaveChangesAsync(_contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); _logger.LogCallInfo(LightlessHubLogger.Args(dto, "Success")); } diff --git a/LightlessSyncServer/LightlessSyncServer/Utils/Extensions.cs b/LightlessSyncServer/LightlessSyncServer/Utils/Extensions.cs index 070ff9e..59d30ba 100644 --- a/LightlessSyncServer/LightlessSyncServer/Utils/Extensions.cs +++ b/LightlessSyncServer/LightlessSyncServer/Utils/Extensions.cs @@ -10,7 +10,7 @@ public static class Extensions { public static GroupData ToGroupData(this Group group) { - return new GroupData(group.GID, group.Alias); + return new GroupData(group.GID, group.Alias, group.CreatedDate, group.Profile.Description, group.Profile.Tags, group.Profile.Base64GroupProfileImage); } public static UserData ToUserData(this GroupPair pair) diff --git a/LightlessSyncServer/LightlessSyncShared/Models/Group.cs b/LightlessSyncServer/LightlessSyncShared/Models/Group.cs index 2188a5b..4d6e26e 100644 --- a/LightlessSyncServer/LightlessSyncShared/Models/Group.cs +++ b/LightlessSyncServer/LightlessSyncShared/Models/Group.cs @@ -9,6 +9,7 @@ public class Group public string GID { get; set; } public string OwnerUID { get; set; } public User Owner { get; set; } + public GroupProfile? Profile { get; set; } [MaxLength(50)] public string Alias { get; set; } public bool InvitesEnabled { get; set; } diff --git a/LightlessSyncServer/LightlessSyncShared/Models/GroupPair.cs b/LightlessSyncServer/LightlessSyncShared/Models/GroupPair.cs index f04db3f..a0b7de8 100644 --- a/LightlessSyncServer/LightlessSyncShared/Models/GroupPair.cs +++ b/LightlessSyncServer/LightlessSyncShared/Models/GroupPair.cs @@ -4,6 +4,7 @@ public class GroupPair { public string GroupGID { get; set; } public Group Group { get; set; } + public GroupProfile Profile { get; set; } public string GroupUserUID { get; set; } public User GroupUser { get; set; } public bool IsPinned { get; set; } diff --git a/LightlessSyncServer/LightlessSyncShared/Models/GroupProfile.cs b/LightlessSyncServer/LightlessSyncShared/Models/GroupProfile.cs index ea750d8..347f79d 100644 --- a/LightlessSyncServer/LightlessSyncShared/Models/GroupProfile.cs +++ b/LightlessSyncServer/LightlessSyncShared/Models/GroupProfile.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LightlessSyncShared.Models; +namespace LightlessSyncShared.Models; public class GroupProfile { public string GroupGID { get; set; } From deea39d62177c1effba28d36f3aa9045261ea378 Mon Sep 17 00:00:00 2001 From: CakeAndBanana Date: Wed, 17 Sep 2025 02:38:20 +0200 Subject: [PATCH 04/17] Added get of group profile, removed group from model. redone group data. --- .../LightlessSyncServer/Hubs/MareHub.Groups.cs | 12 ++++++++++++ .../LightlessSyncServer/Utils/Extensions.cs | 2 +- .../LightlessSyncShared/Models/Group.cs | 1 - 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs b/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs index f0468dd..5241b0c 100644 --- a/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs +++ b/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs @@ -1,6 +1,7 @@ using LightlessSync.API.Data.Enum; using LightlessSync.API.Data.Extensions; using LightlessSync.API.Dto.Group; +using LightlessSync.API.Dto.User; using LightlessSyncServer.Utils; using LightlessSyncShared.Models; using LightlessSyncShared.Utils; @@ -604,6 +605,17 @@ public partial class LightlessHub } } + [Authorize(Policy = "Identified")] + public async Task GroupGetProfile(GroupDto dto) + { + _logger.LogCallInfo(LightlessHubLogger.Args(dto)); + + var data = await DbContext.GroupProfiles.SingleOrDefaultAsync(g => g.GroupGID == dto.Group.GID, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); + if (data == null) return new GroupProfileDto(dto.Group, null, null, null); + + return new GroupProfileDto(dto.Group, data.Description, data.Tags, data.Base64GroupProfileImage); + } + [Authorize(Policy = "Identified")] public async Task GroupSetProfile(GroupProfileDto dto) { diff --git a/LightlessSyncServer/LightlessSyncServer/Utils/Extensions.cs b/LightlessSyncServer/LightlessSyncServer/Utils/Extensions.cs index 59d30ba..34bedac 100644 --- a/LightlessSyncServer/LightlessSyncServer/Utils/Extensions.cs +++ b/LightlessSyncServer/LightlessSyncServer/Utils/Extensions.cs @@ -10,7 +10,7 @@ public static class Extensions { public static GroupData ToGroupData(this Group group) { - return new GroupData(group.GID, group.Alias, group.CreatedDate, group.Profile.Description, group.Profile.Tags, group.Profile.Base64GroupProfileImage); + return new GroupData(group.GID, group.Alias, group.CreatedDate); } public static UserData ToUserData(this GroupPair pair) diff --git a/LightlessSyncServer/LightlessSyncShared/Models/Group.cs b/LightlessSyncServer/LightlessSyncShared/Models/Group.cs index 4d6e26e..2188a5b 100644 --- a/LightlessSyncServer/LightlessSyncShared/Models/Group.cs +++ b/LightlessSyncServer/LightlessSyncShared/Models/Group.cs @@ -9,7 +9,6 @@ public class Group public string GID { get; set; } public string OwnerUID { get; set; } public User Owner { get; set; } - public GroupProfile? Profile { get; set; } [MaxLength(50)] public string Alias { get; set; } public bool InvitesEnabled { get; set; } From b669e2cb24b91d2ce80e479cd45258558c123bd7 Mon Sep 17 00:00:00 2001 From: defnotken Date: Tue, 16 Sep 2025 19:54:31 -0500 Subject: [PATCH 05/17] Adding group profile to the group model --- .../LightlessSyncShared/Data/MareDbContext.cs | 10 +- ...50917004805_AddProfilesToGroup.Designer.cs | 1155 +++++++++++++++++ .../20250917004805_AddProfilesToGroup.cs | 41 + .../LightlessDbContextModelSnapshot.cs | 12 +- .../LightlessSyncShared/Models/Group.cs | 1 + .../Models/GroupProfile.cs | 3 + 6 files changed, 1213 insertions(+), 9 deletions(-) create mode 100644 LightlessSyncServer/LightlessSyncShared/Migrations/20250917004805_AddProfilesToGroup.Designer.cs create mode 100644 LightlessSyncServer/LightlessSyncShared/Migrations/20250917004805_AddProfilesToGroup.cs diff --git a/LightlessSyncServer/LightlessSyncShared/Data/MareDbContext.cs b/LightlessSyncServer/LightlessSyncShared/Data/MareDbContext.cs index 4f38ad8..fe17706 100644 --- a/LightlessSyncServer/LightlessSyncShared/Data/MareDbContext.cs +++ b/LightlessSyncServer/LightlessSyncShared/Data/MareDbContext.cs @@ -74,6 +74,11 @@ public class LightlessDbContext : DbContext mb.Entity() .Property(g => g.CreatedDate) .HasDefaultValueSql("CURRENT_TIMESTAMP"); + mb.Entity() + .HasOne(g => g.Profile) + .WithOne(p => p.Group) + .HasForeignKey(p => p.GroupGID) + .IsRequired(false); mb.Entity().ToTable("group_pairs"); mb.Entity().HasKey(u => new { u.GroupGID, u.GroupUserUID }); mb.Entity().HasIndex(c => c.GroupUserUID); @@ -85,11 +90,6 @@ public class LightlessDbContext : DbContext mb.Entity().ToTable("group_profiles"); mb.Entity().HasKey(u => u.GroupGID); mb.Entity().HasIndex(c => c.GroupGID); - mb.Entity() - .HasOne(gp => gp.Group) - .WithMany() - .HasForeignKey(gp => gp.GroupGID) - .OnDelete(DeleteBehavior.Cascade); mb.Entity().ToTable("group_temp_invites"); mb.Entity().HasKey(u => new { u.GroupGID, u.Invite }); mb.Entity().HasIndex(c => c.GroupGID); diff --git a/LightlessSyncServer/LightlessSyncShared/Migrations/20250917004805_AddProfilesToGroup.Designer.cs b/LightlessSyncServer/LightlessSyncShared/Migrations/20250917004805_AddProfilesToGroup.Designer.cs new file mode 100644 index 0000000..95bcd9b --- /dev/null +++ b/LightlessSyncServer/LightlessSyncShared/Migrations/20250917004805_AddProfilesToGroup.Designer.cs @@ -0,0 +1,1155 @@ +// +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("20250917004805_AddProfilesToGroup")] + partial class AddProfilesToGroup + { + /// + 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("CreatedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_date") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + 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("FromFinder") + .HasColumnType("boolean") + .HasColumnName("from_finder"); + + b.Property("IsModerator") + .HasColumnType("boolean") + .HasColumnName("is_moderator"); + + b.Property("IsPinned") + .HasColumnType("boolean") + .HasColumnName("is_pinned"); + + b.Property("JoinedGroupOn") + .HasColumnType("timestamp with time zone") + .HasColumnName("joined_group_on"); + + 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.GroupProfile", b => + { + b.Property("GroupGID") + .HasMaxLength(20) + .HasColumnType("character varying(20)") + .HasColumnName("group_gid"); + + b.Property("Base64GroupProfileImage") + .HasColumnType("text") + .HasColumnName("base64group_profile_image"); + + b.Property("Description") + .HasColumnType("text") + .HasColumnName("description"); + + b.Property("Tags") + .HasColumnType("text") + .HasColumnName("tags"); + + b.HasKey("GroupGID") + .HasName("pk_group_profiles"); + + b.HasIndex("GroupGID") + .HasDatabaseName("ix_group_profiles_group_gid"); + + b.ToTable("group_profiles", (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.GroupProfile", b => + { + b.HasOne("LightlessSyncShared.Models.Group", "Group") + .WithOne("Profile") + .HasForeignKey("LightlessSyncShared.Models.GroupProfile", "GroupGID") + .HasConstraintName("fk_group_profiles_groups_group_gid"); + + b.Navigation("Group"); + }); + + 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"); + }); + + modelBuilder.Entity("LightlessSyncShared.Models.Group", b => + { + b.Navigation("Profile"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/LightlessSyncServer/LightlessSyncShared/Migrations/20250917004805_AddProfilesToGroup.cs b/LightlessSyncServer/LightlessSyncShared/Migrations/20250917004805_AddProfilesToGroup.cs new file mode 100644 index 0000000..858430c --- /dev/null +++ b/LightlessSyncServer/LightlessSyncShared/Migrations/20250917004805_AddProfilesToGroup.cs @@ -0,0 +1,41 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace LightlessSyncServer.Migrations +{ + /// + public partial class AddProfilesToGroup : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "fk_group_profiles_groups_group_gid", + table: "group_profiles"); + + migrationBuilder.AddForeignKey( + name: "fk_group_profiles_groups_group_gid", + table: "group_profiles", + column: "group_gid", + principalTable: "groups", + principalColumn: "gid"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "fk_group_profiles_groups_group_gid", + table: "group_profiles"); + + migrationBuilder.AddForeignKey( + name: "fk_group_profiles_groups_group_gid", + table: "group_profiles", + column: "group_gid", + principalTable: "groups", + principalColumn: "gid", + onDelete: ReferentialAction.Cascade); + } + } +} diff --git a/LightlessSyncServer/LightlessSyncShared/Migrations/LightlessDbContextModelSnapshot.cs b/LightlessSyncServer/LightlessSyncShared/Migrations/LightlessDbContextModelSnapshot.cs index 391143b..01f6009 100644 --- a/LightlessSyncServer/LightlessSyncShared/Migrations/LightlessDbContextModelSnapshot.cs +++ b/LightlessSyncServer/LightlessSyncShared/Migrations/LightlessDbContextModelSnapshot.cs @@ -585,6 +585,7 @@ namespace LightlessSyncServer.Migrations modelBuilder.Entity("LightlessSyncShared.Models.GroupProfile", b => { b.Property("GroupGID") + .HasMaxLength(20) .HasColumnType("character varying(20)") .HasColumnName("group_gid"); @@ -1054,10 +1055,8 @@ namespace LightlessSyncServer.Migrations modelBuilder.Entity("LightlessSyncShared.Models.GroupProfile", b => { b.HasOne("LightlessSyncShared.Models.Group", "Group") - .WithMany() - .HasForeignKey("GroupGID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() + .WithOne("Profile") + .HasForeignKey("LightlessSyncShared.Models.GroupProfile", "GroupGID") .HasConstraintName("fk_group_profiles_groups_group_gid"); b.Navigation("Group"); @@ -1142,6 +1141,11 @@ namespace LightlessSyncServer.Migrations b.Navigation("Poses"); }); + + modelBuilder.Entity("LightlessSyncShared.Models.Group", b => + { + b.Navigation("Profile"); + }); #pragma warning restore 612, 618 } } diff --git a/LightlessSyncServer/LightlessSyncShared/Models/Group.cs b/LightlessSyncServer/LightlessSyncShared/Models/Group.cs index 2188a5b..522c7d8 100644 --- a/LightlessSyncServer/LightlessSyncShared/Models/Group.cs +++ b/LightlessSyncServer/LightlessSyncShared/Models/Group.cs @@ -11,6 +11,7 @@ public class Group public User Owner { get; set; } [MaxLength(50)] public string Alias { get; set; } + public GroupProfile? Profile { get; set; } public bool InvitesEnabled { get; set; } public string HashedPassword { get; set; } public bool PreferDisableSounds { get; set; } diff --git a/LightlessSyncServer/LightlessSyncShared/Models/GroupProfile.cs b/LightlessSyncServer/LightlessSyncShared/Models/GroupProfile.cs index ea750d8..fdc1717 100644 --- a/LightlessSyncServer/LightlessSyncShared/Models/GroupProfile.cs +++ b/LightlessSyncServer/LightlessSyncShared/Models/GroupProfile.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -7,6 +8,8 @@ using System.Threading.Tasks; namespace LightlessSyncShared.Models; public class GroupProfile { + [Key] + [MaxLength(20)] public string GroupGID { get; set; } public Group Group { get; set; } public string Description { get; set; } From 931ca0d62224fa36f3961cc8e021d67b53ea63fe Mon Sep 17 00:00:00 2001 From: CakeAndBanana Date: Wed, 17 Sep 2025 05:19:37 +0200 Subject: [PATCH 06/17] Added parameters --- .../LightlessSyncServer/Hubs/MareHub.Groups.cs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs b/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs index 5241b0c..9e5b8c2 100644 --- a/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs +++ b/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs @@ -609,11 +609,16 @@ public partial class LightlessHub public async Task GroupGetProfile(GroupDto dto) { _logger.LogCallInfo(LightlessHubLogger.Args(dto)); - - var data = await DbContext.GroupProfiles.SingleOrDefaultAsync(g => g.GroupGID == dto.Group.GID, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); - if (data == null) return new GroupProfileDto(dto.Group, null, null, null); - return new GroupProfileDto(dto.Group, data.Description, data.Tags, data.Base64GroupProfileImage); + var cancellationToken = _contextAccessor.HttpContext.RequestAborted; + + var data = await DbContext.GroupProfiles + .FirstOrDefaultAsync(g => g.GroupGID == dto.Group.GID, cancellationToken) + .ConfigureAwait(false); + + return data == null + ? new GroupProfileDto(dto.Group, null, null, null) + : new GroupProfileDto(dto.Group, data.Description, data.Tags, data.Base64GroupProfileImage); } [Authorize(Policy = "Identified")] From 6fb5f6e9a7f8171fda530dd4708ffb95cb8e907f Mon Sep 17 00:00:00 2001 From: CakeAndBanana Date: Wed, 17 Sep 2025 05:37:04 +0200 Subject: [PATCH 07/17] Added client sendback of profileDTO --- LightlessAPI | 2 +- .../Hubs/MareHub.ClientStubs.cs | 19 +------- .../Hubs/MareHub.Groups.cs | 45 ++++++++++++------- .../LightlessSyncServer/Hubs/MareHub.User.cs | 20 ++++----- 4 files changed, 41 insertions(+), 45 deletions(-) diff --git a/LightlessAPI b/LightlessAPI index 4ce70be..96744f4 160000 --- a/LightlessAPI +++ b/LightlessAPI @@ -1 +1 @@ -Subproject commit 4ce70bee8354d0c96d73e65312d39a826810dc60 +Subproject commit 96744f4f28142a5cd40103d6ee209761b354b818 diff --git a/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.ClientStubs.cs b/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.ClientStubs.cs index d148f91..c4fbe0c 100644 --- a/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.ClientStubs.cs +++ b/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.ClientStubs.cs @@ -10,41 +10,24 @@ namespace LightlessSyncServer.Hubs public partial class LightlessHub { public Task Client_DownloadReady(Guid requestId) => throw new PlatformNotSupportedException("Calling clientside method on server not supported"); - public Task Client_GroupChangePermissions(GroupPermissionDto groupPermission) => throw new PlatformNotSupportedException("Calling clientside method on server not supported"); - public Task Client_GroupDelete(GroupDto groupDto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported"); - public Task Client_GroupPairChangeUserInfo(GroupPairUserInfoDto dto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported"); - public Task Client_GroupPairJoined(GroupPairFullInfoDto groupPairInfoDto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported"); - public Task Client_GroupPairLeft(GroupPairDto groupPairDto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported"); - public Task Client_GroupSendFullInfo(GroupFullInfoDto groupInfo) => throw new PlatformNotSupportedException("Calling clientside method on server not supported"); - + public Task Client_GroupSendProfile(GroupProfileDto groupProfile) => throw new PlatformNotSupportedException("Calling clientside method on server not supported"); public Task Client_GroupSendInfo(GroupInfoDto dto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported"); - public Task Client_ReceiveServerMessage(MessageSeverity messageSeverity, string message) => throw new PlatformNotSupportedException("Calling clientside method on server not supported"); - public Task Client_UpdateSystemInfo(SystemInfoDto systemInfo) => throw new PlatformNotSupportedException("Calling clientside method on server not supported"); - public Task Client_UserAddClientPair(UserPairDto dto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported"); - public Task Client_UserReceiveCharacterData(OnlineUserCharaDataDto dataDto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported"); - public Task Client_UserReceiveUploadStatus(UserDto dto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported"); - public Task Client_UserRemoveClientPair(UserDto dto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported"); - public Task Client_UserSendOffline(UserDto dto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported"); - public Task Client_UserSendOnline(OnlineUserIdentDto dto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported"); - public Task Client_UserUpdateOtherPairPermissions(UserPermissionsDto dto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported"); - public Task Client_UserUpdateProfile(UserDto dto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported"); - public Task Client_UserUpdateSelfPairPermissions(UserPermissionsDto dto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported"); public Task Client_UserUpdateDefaultPermissions(DefaultPermissionsDto dto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported"); public Task Client_UpdateUserIndividualPairStatusDto(UserIndividualPairStatusDto dto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported"); diff --git a/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs b/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs index 9e5b8c2..24bb313 100644 --- a/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs +++ b/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs @@ -1,7 +1,6 @@ using LightlessSync.API.Data.Enum; using LightlessSync.API.Data.Extensions; using LightlessSync.API.Dto.Group; -using LightlessSync.API.Dto.User; using LightlessSyncServer.Utils; using LightlessSyncShared.Models; using LightlessSyncShared.Utils; @@ -136,7 +135,7 @@ public partial class LightlessHub var allUserPairs = await GetAllPairInfo(pair.GroupUserUID).ConfigureAwait(false); - var sharedData = await DbContext.CharaDataAllowances.Where(u => u.AllowedGroup != null && u.AllowedGroupGID == dto.GID && u.ParentUploaderUID == pair.GroupUserUID).ToListAsync().ConfigureAwait(false); + var sharedData = await DbContext.CharaDataAllowances.Where(u => u.AllowedGroup != null && u.AllowedGroupGID == dto.GID && u.ParentUploaderUID == pair.GroupUserUID).ToListAsync(cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); DbContext.CharaDataAllowances.RemoveRange(sharedData); foreach (var groupUserPair in groupPairs.Where(p => !string.Equals(p.GroupUserUID, pair.GroupUserUID, StringComparison.Ordinal))) @@ -330,14 +329,14 @@ public partial class LightlessHub _logger.LogCallInfo(LightlessHubLogger.Args(dto)); - var group = await DbContext.Groups.Include(g => g.Owner).AsNoTracking().SingleOrDefaultAsync(g => g.GID == aliasOrGid || g.Alias == aliasOrGid).ConfigureAwait(false); + var group = await DbContext.Groups.Include(g => g.Owner).AsNoTracking().SingleOrDefaultAsync(g => g.GID == aliasOrGid || g.Alias == aliasOrGid, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); var groupGid = group?.GID ?? string.Empty; - var existingPair = await DbContext.GroupPairs.AsNoTracking().SingleOrDefaultAsync(g => g.GroupGID == groupGid && g.GroupUserUID == UserUID).ConfigureAwait(false); + var existingPair = await DbContext.GroupPairs.AsNoTracking().SingleOrDefaultAsync(g => g.GroupGID == groupGid && g.GroupUserUID == UserUID, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); var hashedPw = StringUtils.Sha256String(dto.Password); - var existingUserCount = await DbContext.GroupPairs.AsNoTracking().CountAsync(g => g.GroupGID == groupGid).ConfigureAwait(false); - var joinedGroups = await DbContext.GroupPairs.CountAsync(g => g.GroupUserUID == UserUID).ConfigureAwait(false); - var isBanned = await DbContext.GroupBans.AnyAsync(g => g.GroupGID == groupGid && g.BannedUserUID == UserUID).ConfigureAwait(false); - var oneTimeInvite = await DbContext.GroupTempInvites.SingleOrDefaultAsync(g => g.GroupGID == groupGid && g.Invite == hashedPw).ConfigureAwait(false); + var existingUserCount = await DbContext.GroupPairs.AsNoTracking().CountAsync(g => g.GroupGID == groupGid, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); + var joinedGroups = await DbContext.GroupPairs.CountAsync(g => g.GroupUserUID == UserUID, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); + var isBanned = await DbContext.GroupBans.AnyAsync(g => g.GroupGID == groupGid && g.BannedUserUID == UserUID, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); + var oneTimeInvite = await DbContext.GroupTempInvites.SingleOrDefaultAsync(g => g.GroupGID == groupGid && g.Invite == hashedPw, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); if (group == null || (!string.Equals(group.HashedPassword, hashedPw, StringComparison.Ordinal) && oneTimeInvite == null) @@ -364,7 +363,7 @@ public partial class LightlessHub JoinedGroupOn = DateTime.UtcNow, }; - var preferredPermissions = await DbContext.GroupPairPreferredPermissions.SingleOrDefaultAsync(u => u.UserUID == UserUID && u.GroupGID == group.GID).ConfigureAwait(false); + var preferredPermissions = await DbContext.GroupPairPreferredPermissions.SingleOrDefaultAsync(u => u.UserUID == UserUID && u.GroupGID == group.GID, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); if (preferredPermissions == null) { GroupPairPreferredPermission newPerms = new() @@ -560,7 +559,7 @@ public partial class LightlessHub .Client_GroupPairLeft(new GroupPairDto(dto.Group, pair.GroupUser.ToUserData())).ConfigureAwait(false); } - await DbContext.SaveChangesAsync().ConfigureAwait(false); + await DbContext.SaveChangesAsync(_contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); return usersToPrune.Count(); } @@ -584,15 +583,15 @@ public partial class LightlessHub var groupPairs = DbContext.GroupPairs.Where(p => p.GroupGID == group.GID).AsNoTracking().ToList(); await Clients.Users(groupPairs.Select(p => p.GroupUserUID)).Client_GroupPairLeft(dto).ConfigureAwait(false); - var sharedData = await DbContext.CharaDataAllowances.Where(u => u.AllowedGroup != null && u.AllowedGroupGID == dto.GID && u.ParentUploaderUID == dto.UID).ToListAsync().ConfigureAwait(false); + var sharedData = await DbContext.CharaDataAllowances.Where(u => u.AllowedGroup != null && u.AllowedGroupGID == dto.GID && u.ParentUploaderUID == dto.UID).ToListAsync(cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); DbContext.CharaDataAllowances.RemoveRange(sharedData); - await DbContext.SaveChangesAsync().ConfigureAwait(false); + await DbContext.SaveChangesAsync(_contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); var userIdent = await GetUserIdent(dto.User.UID).ConfigureAwait(false); if (userIdent == null) { - await DbContext.SaveChangesAsync().ConfigureAwait(false); + await DbContext.SaveChangesAsync(_contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); return; } @@ -616,9 +615,23 @@ public partial class LightlessHub .FirstOrDefaultAsync(g => g.GroupGID == dto.Group.GID, cancellationToken) .ConfigureAwait(false); - return data == null - ? new GroupProfileDto(dto.Group, null, null, null) - : new GroupProfileDto(dto.Group, data.Description, data.Tags, data.Base64GroupProfileImage); + var profileDto = new GroupProfileDto(dto.Group, Description: null, Tags: null, PictureBase64: null); + + if (data is not null) + { + profileDto = profileDto with + { + Description = data.Description, + Tags = data.Tags, + PictureBase64 = data.Base64GroupProfileImage, + }; + + await Clients.User(UserUID) + .Client_GroupSendProfile(profileDto) + .ConfigureAwait(false); + } + + return profileDto; } [Authorize(Policy = "Identified")] diff --git a/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.User.cs b/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.User.cs index 53162a2..0ea7d14 100644 --- a/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.User.cs +++ b/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.User.cs @@ -30,7 +30,7 @@ public partial class LightlessHub if (string.Equals(dto.User.UID, UserUID, StringComparison.Ordinal) || string.IsNullOrWhiteSpace(dto.User.UID)) return; // grab other user, check if it exists and if a pair already exists - var otherUser = await DbContext.Users.SingleOrDefaultAsync(u => u.UID == uid || u.Alias == uid).ConfigureAwait(false); + var otherUser = await DbContext.Users.SingleOrDefaultAsync(u => u.UID == uid || u.Alias == uid, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); if (otherUser == null) { await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Warning, $"Cannot pair with {dto.User.UID}, UID does not exist").ConfigureAwait(false); @@ -46,7 +46,7 @@ public partial class LightlessHub var existingEntry = await DbContext.ClientPairs.AsNoTracking() .FirstOrDefaultAsync(p => - p.User.UID == UserUID && p.OtherUserUID == otherUser.UID).ConfigureAwait(false); + p.User.UID == UserUID && p.OtherUserUID == otherUser.UID, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); if (existingEntry != null) { @@ -55,11 +55,11 @@ public partial class LightlessHub } // grab self create new client pair and save - var user = await DbContext.Users.SingleAsync(u => u.UID == UserUID).ConfigureAwait(false); + var user = await DbContext.Users.SingleAsync(u => u.UID == UserUID, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); _logger.LogCallInfo(LightlessHubLogger.Args(dto, "Success")); - ClientPair wl = new ClientPair() + ClientPair wl = new() { OtherUser = otherUser, User = user, @@ -71,7 +71,7 @@ public partial class LightlessHub var permissions = existingData?.OwnPermissions; if (permissions == null || !permissions.Sticky) { - var ownDefaultPermissions = await DbContext.UserDefaultPreferredPermissions.AsNoTracking().SingleOrDefaultAsync(f => f.UserUID == UserUID).ConfigureAwait(false); + var ownDefaultPermissions = await DbContext.UserDefaultPreferredPermissions.AsNoTracking().SingleOrDefaultAsync(f => f.UserUID == UserUID, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); permissions = new UserPermissionSet() { @@ -84,7 +84,7 @@ public partial class LightlessHub Sticky = true }; - var existingDbPerms = await DbContext.Permissions.SingleOrDefaultAsync(u => u.UserUID == UserUID && u.OtherUserUID == otherUser.UID).ConfigureAwait(false); + var existingDbPerms = await DbContext.Permissions.SingleOrDefaultAsync(u => u.UserUID == UserUID && u.OtherUserUID == otherUser.UID, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); if (existingDbPerms == null) { await DbContext.Permissions.AddAsync(permissions).ConfigureAwait(false); @@ -142,7 +142,7 @@ public partial class LightlessHub { _logger.LogCallInfo(); - var userEntry = await DbContext.Users.SingleAsync(u => u.UID == UserUID).ConfigureAwait(false); + var userEntry = await DbContext.Users.SingleAsync(u => u.UID == UserUID, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); 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) { @@ -195,7 +195,7 @@ public partial class LightlessHub return new UserProfileDto(user.User, false, null, null, "Due to the pause status you cannot access this users profile."); } - var data = await DbContext.UserProfileData.SingleOrDefaultAsync(u => u.UserUID == user.User.UID).ConfigureAwait(false); + var data = await DbContext.UserProfileData.SingleOrDefaultAsync(u => u.UserUID == user.User.UID, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); if (data == null) return new UserProfileDto(user.User, false, null, null, null); if (data.FlaggedForReport) return new UserProfileDto(user.User, true, null, null, "This profile is flagged for report and pending evaluation"); @@ -296,7 +296,7 @@ public partial class LightlessHub // check if client pair even exists ClientPair callerPair = - await DbContext.ClientPairs.SingleOrDefaultAsync(w => w.UserUID == UserUID && w.OtherUserUID == dto.User.UID).ConfigureAwait(false); + await DbContext.ClientPairs.SingleOrDefaultAsync(w => w.UserUID == UserUID && w.OtherUserUID == dto.User.UID, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); if (callerPair == null) return; var pairData = await GetPairInfo(UserUID, dto.User.UID).ConfigureAwait(false); @@ -347,7 +347,7 @@ public partial class LightlessHub if (!string.Equals(dto.User.UID, UserUID, StringComparison.Ordinal)) throw new HubException("Cannot modify profile data for anyone but yourself"); - var existingData = await DbContext.UserProfileData.SingleOrDefaultAsync(u => u.UserUID == dto.User.UID).ConfigureAwait(false); + var existingData = await DbContext.UserProfileData.SingleOrDefaultAsync(u => u.UserUID == dto.User.UID, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); if (existingData?.FlaggedForReport ?? false) { From 71c01461aed6d1ace7e52f3efbe72f0190cd2800 Mon Sep 17 00:00:00 2001 From: CakeAndBanana Date: Wed, 24 Sep 2025 15:04:02 +0200 Subject: [PATCH 08/17] Lightfinder merge into group changes --- LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs b/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs index 24bb313..d174224 100644 --- a/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs +++ b/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs @@ -719,7 +719,7 @@ public partial class LightlessHub .ToDictionary(u => groups.First(f => string.Equals(f.GroupGID, u.GroupGID, StringComparison.Ordinal)), u => u); var groupInfos = await DbContext.GroupPairs.Where(u => groups.Select(g => g.GroupGID).Contains(u.GroupGID) && (u.IsPinned || u.IsModerator)) .ToListAsync(cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); - + return preferredPermissions.Select(g => new GroupFullInfoDto(g.Key.Group.ToGroupData(), g.Key.Group.Owner.ToUserData(), g.Key.Group.ToEnum(), g.Value.ToEnum(), g.Key.ToEnum(), g.Key.JoinedGroupOn, groupInfos.Where(i => string.Equals(i.GroupGID, g.Key.GroupGID, StringComparison.Ordinal)) From 03f633a2735ac3f2cd88d8726fa5767c8716d6b5 Mon Sep 17 00:00:00 2001 From: CakeAndBanana Date: Thu, 25 Sep 2025 02:03:15 +0200 Subject: [PATCH 09/17] Added lightless finder in dto of joining --- LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs b/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs index 1e157d1..2630a8f 100644 --- a/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs +++ b/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs @@ -370,6 +370,7 @@ public partial class LightlessHub GroupGID = group.GID, GroupUserUID = UserUID, JoinedGroupOn = DateTime.UtcNow, + FromFinder = dto.Finder }; var preferredPermissions = await DbContext.GroupPairPreferredPermissions.SingleOrDefaultAsync(u => u.UserUID == UserUID && u.GroupGID == group.GID, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); @@ -617,7 +618,6 @@ public partial class LightlessHub return new GroupJoinInfoDto(group.ToGroupData(), group.Owner.ToUserData(), group.ToEnum(), true); } - [Authorize(Policy = "Identified")] public async Task GroupLeave(GroupDto dto) { From 1a97dded9c8f770e607de6966f8d1a470f2bdde9 Mon Sep 17 00:00:00 2001 From: CakeAndBanana Date: Thu, 25 Sep 2025 03:14:09 +0200 Subject: [PATCH 10/17] Removal of an accidental change I did. --- LightlessSyncServer/LightlessSyncShared/Models/GroupPair.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/LightlessSyncServer/LightlessSyncShared/Models/GroupPair.cs b/LightlessSyncServer/LightlessSyncShared/Models/GroupPair.cs index a0b7de8..f04db3f 100644 --- a/LightlessSyncServer/LightlessSyncShared/Models/GroupPair.cs +++ b/LightlessSyncServer/LightlessSyncShared/Models/GroupPair.cs @@ -4,7 +4,6 @@ public class GroupPair { public string GroupGID { get; set; } public Group Group { get; set; } - public GroupProfile Profile { get; set; } public string GroupUserUID { get; set; } public User GroupUser { get; set; } public bool IsPinned { get; set; } From 3a4a934d09189a2619f6d7ecd6a8608aad74b60e Mon Sep 17 00:00:00 2001 From: CakeAndBanana Date: Thu, 25 Sep 2025 03:37:13 +0200 Subject: [PATCH 11/17] Revert of GroupFullInfoDto --- .../LightlessSyncServer/Hubs/MareHub.Groups.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs b/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs index 2630a8f..c7a4741 100644 --- a/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs +++ b/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs @@ -211,9 +211,9 @@ public partial class LightlessHub var self = await DbContext.Users.SingleAsync(u => u.UID == UserUID, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); await Clients.User(UserUID).Client_GroupSendFullInfo(new GroupFullInfoDto(newGroup.ToGroupData(), self.ToUserData(), - newGroup.ToEnum(), initialPrefPermissions.ToEnum(), initialPair.ToEnum(), initialPair.JoinedGroupOn, new(StringComparer.Ordinal))) + newGroup.ToEnum(), initialPrefPermissions.ToEnum(), initialPair.ToEnum(), new(StringComparer.Ordinal))) .ConfigureAwait(false); - + _logger.LogCallInfo(LightlessHubLogger.Args(gid)); return new GroupJoinDto(newGroup.ToGroupData(), passwd, initialPrefPermissions.ToEnum()); @@ -406,7 +406,7 @@ public partial class LightlessHub var groupInfos = await DbContext.GroupPairs.Where(u => u.GroupGID == group.GID && (u.IsPinned || u.IsModerator)).ToListAsync(cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); await Clients.User(UserUID).Client_GroupSendFullInfo(new GroupFullInfoDto(group.ToGroupData(), group.Owner.ToUserData(), - group.ToEnum(), preferredPermissions.ToEnum(), newPair.ToEnum(), newPair.JoinedGroupOn, + group.ToEnum(), preferredPermissions.ToEnum(), newPair.ToEnum(), groupInfos.ToDictionary(u => u.GroupUserUID, u => u.ToEnum(), StringComparer.Ordinal))).ConfigureAwait(false); var self = DbContext.Users.Single(u => u.UID == UserUID); @@ -812,7 +812,7 @@ public partial class LightlessHub .ToListAsync(cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); return preferredPermissions.Select(g => new GroupFullInfoDto(g.Key.Group.ToGroupData(), g.Key.Group.Owner.ToUserData(), - g.Key.Group.ToEnum(), g.Value.ToEnum(), g.Key.ToEnum(), g.Key.JoinedGroupOn, + g.Key.Group.ToEnum(), g.Value.ToEnum(), g.Key.ToEnum(), groupInfos.Where(i => string.Equals(i.GroupGID, g.Key.GroupGID, StringComparison.Ordinal)) .ToDictionary(i => i.GroupUserUID, i => i.ToEnum(), StringComparer.Ordinal))).ToList(); } From bf380688c83f0c750fe5903b8e223a5167868893 Mon Sep 17 00:00:00 2001 From: CakeAndBanana Date: Thu, 25 Sep 2025 04:28:52 +0200 Subject: [PATCH 12/17] Redoing of groupsgetall --- .../Hubs/MareHub.Groups.cs | 48 ++++++++++++++----- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs b/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs index c7a4741..7c1fc0a 100644 --- a/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs +++ b/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs @@ -192,6 +192,7 @@ public partial class LightlessHub GroupUserUID = UserUID, IsPinned = true, JoinedGroupOn = currentTime, + FromFinder = false, }; GroupPairPreferredPermission initialPrefPermissions = new() @@ -804,17 +805,42 @@ public partial class LightlessHub { _logger.LogCallInfo(); - var groups = await DbContext.GroupPairs.Include(g => g.Group).Include(g => g.Group.Owner).Where(g => g.GroupUserUID == UserUID).AsNoTracking().ToListAsync(cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); - var preferredPermissions = (await DbContext.GroupPairPreferredPermissions.Where(u => u.UserUID == UserUID).ToListAsync(cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false)) - .Where(u => groups.Exists(k => string.Equals(k.GroupGID, u.GroupGID, StringComparison.Ordinal))) - .ToDictionary(u => groups.First(f => string.Equals(f.GroupGID, u.GroupGID, StringComparison.Ordinal)), u => u); - var groupInfos = await DbContext.GroupPairs.Where(u => groups.Select(g => g.GroupGID).Contains(u.GroupGID) && (u.IsPinned || u.IsModerator)) - .ToListAsync(cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); - - return preferredPermissions.Select(g => new GroupFullInfoDto(g.Key.Group.ToGroupData(), g.Key.Group.Owner.ToUserData(), - g.Key.Group.ToEnum(), g.Value.ToEnum(), g.Key.ToEnum(), - groupInfos.Where(i => string.Equals(i.GroupGID, g.Key.GroupGID, StringComparison.Ordinal)) - .ToDictionary(i => i.GroupUserUID, i => i.ToEnum(), StringComparer.Ordinal))).ToList(); + var ct = _contextAccessor.HttpContext.RequestAborted; + + var result = await ( + from gp in DbContext.GroupPairs + .Include(gp => gp.Group) + .ThenInclude(g => g.Owner) + join pp in DbContext.GroupPairPreferredPermissions + on new { gp.GroupGID, UserUID } equals new { pp.GroupGID, pp.UserUID } + where gp.GroupUserUID == UserUID + select new + { + GroupPair = gp, + PreferredPermission = pp, + GroupInfos = DbContext.GroupPairs + .Where(x => x.GroupGID == gp.GroupGID && (x.IsPinned || x.IsModerator)) + .Select(x => new { x.GroupUserUID, EnumValue = x.ToEnum() }) + .ToList() // forces subquery per row + }) + .AsNoTracking() + .ToListAsync(ct) + .ConfigureAwait(false); + + return [.. result.Select(r => + { + var groupInfoDict = r.GroupInfos + .ToDictionary(x => x.GroupUserUID, x => x.EnumValue, StringComparer.Ordinal); + + return new GroupFullInfoDto( + r.GroupPair.Group.ToGroupData(), + r.GroupPair.Group.Owner.ToUserData(), + r.GroupPair.Group.ToEnum(), + r.PreferredPermission.ToEnum(), + r.GroupPair.ToEnum(), + groupInfoDict + ); + })]; } [Authorize(Policy = "Identified")] From 825bb3b7d692cf2beb36f140e62294556d22796a Mon Sep 17 00:00:00 2001 From: CakeAndBanana Date: Thu, 25 Sep 2025 04:34:25 +0200 Subject: [PATCH 13/17] Cleaned up a bit. --- .../LightlessSyncServer/Hubs/MareHub.Groups.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs b/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs index 7c1fc0a..5e02ba4 100644 --- a/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs +++ b/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs @@ -821,13 +821,13 @@ public partial class LightlessHub GroupInfos = DbContext.GroupPairs .Where(x => x.GroupGID == gp.GroupGID && (x.IsPinned || x.IsModerator)) .Select(x => new { x.GroupUserUID, EnumValue = x.ToEnum() }) - .ToList() // forces subquery per row + .ToList(), }) .AsNoTracking() .ToListAsync(ct) .ConfigureAwait(false); - return [.. result.Select(r => + List List = [.. result.Select(r => { var groupInfoDict = r.GroupInfos .ToDictionary(x => x.GroupUserUID, x => x.EnumValue, StringComparer.Ordinal); @@ -840,7 +840,8 @@ public partial class LightlessHub r.GroupPair.ToEnum(), groupInfoDict ); - })]; + }),]; + return List; } [Authorize(Policy = "Identified")] From 81e773e0c46b9c2b1d87124fd034f261e8cc94e6 Mon Sep 17 00:00:00 2001 From: CakeAndBanana Date: Thu, 25 Sep 2025 05:24:07 +0200 Subject: [PATCH 14/17] Updated submodule --- LightlessAPI | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LightlessAPI b/LightlessAPI index 96744f4..a337481 160000 --- a/LightlessAPI +++ b/LightlessAPI @@ -1 +1 @@ -Subproject commit 96744f4f28142a5cd40103d6ee209761b354b818 +Subproject commit a337481243a11490f3a115ca1ac0abfdd62c0554 From 7fecea2c6fa69dc9216cbf2501a89c86cbba5738 Mon Sep 17 00:00:00 2001 From: CakeAndBanana Date: Thu, 25 Sep 2025 05:24:54 +0200 Subject: [PATCH 15/17] Updated Submodule to groups --- LightlessAPI | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LightlessAPI b/LightlessAPI index a337481..69055b0 160000 --- a/LightlessAPI +++ b/LightlessAPI @@ -1 +1 @@ -Subproject commit a337481243a11490f3a115ca1ac0abfdd62c0554 +Subproject commit 69055b0f323e6d35f55750fd1dc5659a8e36b085 From f9f25829a033edc64104c213e6ac2d239c594e2d Mon Sep 17 00:00:00 2001 From: defnotken Date: Thu, 25 Sep 2025 10:00:16 -0500 Subject: [PATCH 16/17] Add logging to test --- .../LightlessSyncServer/Hubs/MareHub.Groups.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs b/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs index 5e02ba4..f4e364f 100644 --- a/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs +++ b/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs @@ -827,11 +827,16 @@ public partial class LightlessHub .ToListAsync(ct) .ConfigureAwait(false); + _logger.LogCallInfo(LightlessHubLogger.Args(result)); + List List = [.. result.Select(r => { var groupInfoDict = r.GroupInfos .ToDictionary(x => x.GroupUserUID, x => x.EnumValue, StringComparer.Ordinal); + + _logger.LogCallInfo(LightlessHubLogger.Args(r)); + return new GroupFullInfoDto( r.GroupPair.Group.ToGroupData(), r.GroupPair.Group.Owner.ToUserData(), From 39aded4fb7dab5820b78aad1db24f69d2257ef58 Mon Sep 17 00:00:00 2001 From: CakeAndBanana Date: Thu, 25 Sep 2025 17:42:09 +0200 Subject: [PATCH 17/17] Changed prefix of syncshells from MSS to LSS --- .../LightlessSyncServer/Hubs/MareHub.Groups.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs b/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs index f4e364f..768fe21 100644 --- a/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs +++ b/LightlessSyncServer/LightlessSyncServer/Hubs/MareHub.Groups.cs @@ -161,11 +161,11 @@ public partial class LightlessHub } var gid = StringUtils.GenerateRandomString(12); - while (await DbContext.Groups.AnyAsync(g => g.GID == "MSS-" + gid, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false)) + while (await DbContext.Groups.AnyAsync(g => g.GID == "LSS-" + gid, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false)) { gid = StringUtils.GenerateRandomString(12); } - gid = "MSS-" + gid; + gid = "LSS-" + gid; var passwd = StringUtils.GenerateRandomString(16); using var sha = SHA256.Create();