diff --git a/api/ExpressedRealms.DB/Characters/Character.cs b/api/ExpressedRealms.DB/Characters/Character.cs index f8374c11..d34b1038 100644 --- a/api/ExpressedRealms.DB/Characters/Character.cs +++ b/api/ExpressedRealms.DB/Characters/Character.cs @@ -21,7 +21,7 @@ public class Character : ISoftDelete public byte IntelligenceId { get; set; } public byte WillpowerId { get; set; } - public int FactionId { get; set; } + public int? FactionId { get; set; } public int StatExperiencePoints { get; set; } @@ -37,6 +37,6 @@ public class Character : ISoftDelete public virtual StatLevel StrengthStatLevel { get; set; } = null!; public virtual StatLevel IntelligenceStatLevel { get; set; } = null!; public virtual StatLevel WillpowerStatLevel { get; set; } = null!; - public virtual ExpressionSection FactionInfo { get; set; } = null!; + public virtual ExpressionSection? FactionInfo { get; set; } = null!; public virtual List CharacterSkillsMappings { get; set; } = null!; } diff --git a/api/ExpressedRealms.DB/Characters/CharacterConfiguration.cs b/api/ExpressedRealms.DB/Characters/CharacterConfiguration.cs index e2fe97ee..5a0e30d1 100644 --- a/api/ExpressedRealms.DB/Characters/CharacterConfiguration.cs +++ b/api/ExpressedRealms.DB/Characters/CharacterConfiguration.cs @@ -21,7 +21,7 @@ public void Configure(EntityTypeBuilder builder) builder.Property(x => x.IntelligenceId).IsRequired().HasDefaultValue(1); builder.Property(x => x.WillpowerId).IsRequired().HasDefaultValue(1); - builder.Property(x => x.FactionId).IsRequired().HasDefaultValue(1); + builder.Property(x => x.FactionId); builder.Property(x => x.StatExperiencePoints).IsRequired().HasDefaultValue(72); @@ -87,7 +87,6 @@ public void Configure(EntityTypeBuilder builder) .HasOne(x => x.FactionInfo) .WithMany(x => x.CharactersList) .HasForeignKey(x => x.FactionId) - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); + .OnDelete(DeleteBehavior.Restrict); } } diff --git a/api/ExpressedRealms.DB/Migrations/20240917054709_MakeFactionsOptionalOnCharacter.Designer.cs b/api/ExpressedRealms.DB/Migrations/20240917054709_MakeFactionsOptionalOnCharacter.Designer.cs new file mode 100644 index 00000000..8236af5b --- /dev/null +++ b/api/ExpressedRealms.DB/Migrations/20240917054709_MakeFactionsOptionalOnCharacter.Designer.cs @@ -0,0 +1,989 @@ +// +using System; +using ExpressedRealms.DB; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace ExpressedRealms.DB.Migrations +{ + [DbContext(typeof(ExpressedRealmsDbContext))] + [Migration("20240917054709_MakeFactionsOptionalOnCharacter")] + partial class MakeFactionsOptionalOnCharacter + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("ExpressedRealms.DB.Characters.Character", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AgilityId") + .ValueGeneratedOnAdd() + .HasColumnType("smallint") + .HasDefaultValue((byte)1); + + b.Property("Background") + .HasColumnType("text"); + + b.Property("ConstitutionId") + .ValueGeneratedOnAdd() + .HasColumnType("smallint") + .HasDefaultValue((byte)1); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DexterityId") + .ValueGeneratedOnAdd() + .HasColumnType("smallint") + .HasDefaultValue((byte)1); + + b.Property("ExpressionId") + .HasColumnType("integer"); + + b.Property("FactionId") + .HasColumnType("integer"); + + b.Property("IntelligenceId") + .ValueGeneratedOnAdd() + .HasColumnType("smallint") + .HasDefaultValue((byte)1); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.Property("PlayerId") + .HasColumnType("uuid"); + + b.Property("StatExperiencePoints") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(72); + + b.Property("StrengthId") + .ValueGeneratedOnAdd() + .HasColumnType("smallint") + .HasDefaultValue((byte)1); + + b.Property("WillpowerId") + .ValueGeneratedOnAdd() + .HasColumnType("smallint") + .HasDefaultValue((byte)1); + + b.HasKey("Id"); + + b.HasIndex("AgilityId"); + + b.HasIndex("ConstitutionId"); + + b.HasIndex("DexterityId"); + + b.HasIndex("ExpressionId"); + + b.HasIndex("FactionId"); + + b.HasIndex("IntelligenceId"); + + b.HasIndex("PlayerId"); + + b.HasIndex("StrengthId"); + + b.HasIndex("WillpowerId"); + + b.ToTable("Characters"); + }); + + modelBuilder.Entity("ExpressedRealms.DB.Models.Expressions.Expression", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("NavMenuImage") + .IsRequired() + .HasColumnType("text"); + + b.Property("ShortDescription") + .IsRequired() + .HasMaxLength(125) + .HasColumnType("character varying(125)"); + + b.HasKey("Id"); + + b.ToTable("Expressions", (string)null); + }); + + modelBuilder.Entity("ExpressedRealms.DB.Models.Expressions.ExpressionSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Content") + .IsRequired() + .HasColumnType("text"); + + b.Property("ExpressionId") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.Property("ParentId") + .HasColumnType("integer"); + + b.Property("SectionTypeId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ExpressionId"); + + b.HasIndex("ParentId"); + + b.HasIndex("SectionTypeId"); + + b.ToTable("ExpressionSections", (string)null); + }); + + modelBuilder.Entity("ExpressedRealms.DB.Models.Expressions.ExpressionSectionType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Id"); + + b.ToTable("ExpressionSectionTypes", (string)null); + }); + + modelBuilder.Entity("ExpressedRealms.DB.Models.Skills.CharacterSkillsMapping", b => + { + b.Property("CharacterId") + .HasColumnType("integer"); + + b.Property("SkillLevelId") + .HasColumnType("smallint"); + + b.Property("SkillTypeId") + .HasColumnType("smallint"); + + b.HasKey("CharacterId", "SkillLevelId", "SkillTypeId"); + + b.HasIndex("SkillLevelId"); + + b.HasIndex("SkillTypeId"); + + b.ToTable("CharacterSkillsMapping", (string)null); + }); + + modelBuilder.Entity("ExpressedRealms.DB.Models.Skills.ModifierType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("smallint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Description") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Id"); + + b.ToTable("ModifierType", (string)null); + }); + + modelBuilder.Entity("ExpressedRealms.DB.Models.Skills.SkillLevel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("smallint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Level") + .HasColumnType("smallint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("XP") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("SkillLevel", (string)null); + }); + + modelBuilder.Entity("ExpressedRealms.DB.Models.Skills.SkillLevelBenefit", b => + { + b.Property("SkillLevelId") + .HasColumnType("smallint"); + + b.Property("SkillTypeId") + .HasColumnType("smallint"); + + b.Property("ModifierTypeId") + .HasColumnType("smallint"); + + b.Property("Modifier") + .HasColumnType("smallint"); + + b.HasKey("SkillLevelId", "SkillTypeId", "ModifierTypeId"); + + b.HasIndex("ModifierTypeId"); + + b.HasIndex("SkillTypeId"); + + b.ToTable("SkillLevelBenefit", (string)null); + }); + + modelBuilder.Entity("ExpressedRealms.DB.Models.Skills.SkillSubType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("smallint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Description") + .IsRequired() + .HasMaxLength(125) + .HasColumnType("character varying(125)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.HasKey("Id"); + + b.ToTable("SkillSubType", (string)null); + }); + + modelBuilder.Entity("ExpressedRealms.DB.Models.Skills.SkillType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("smallint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Description") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(25) + .HasColumnType("character varying(25)"); + + b.Property("SkillSubTypeId") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("SkillSubTypeId"); + + b.ToTable("SkillType", (string)null); + }); + + modelBuilder.Entity("ExpressedRealms.DB.Models.Statistics.StatDescriptionMapping", b => + { + b.Property("StatTypeId") + .HasColumnType("smallint"); + + b.Property("StatLevelId") + .HasColumnType("smallint"); + + b.Property("ReasonableExpectation") + .IsRequired() + .HasMaxLength(400) + .HasColumnType("character varying(400)"); + + b.HasKey("StatTypeId", "StatLevelId"); + + b.HasIndex("StatLevelId"); + + b.ToTable("StatDescriptionMappings"); + }); + + modelBuilder.Entity("ExpressedRealms.DB.Models.Statistics.StatLevel", b => + { + b.Property("Id") + .HasColumnType("smallint"); + + b.Property("Bonus") + .HasColumnType("integer"); + + b.Property("TotalXPCost") + .HasColumnType("integer"); + + b.Property("XPCost") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("StatLevels"); + }); + + modelBuilder.Entity("ExpressedRealms.DB.Models.Statistics.StatType", b => + { + b.Property("Id") + .HasColumnType("smallint"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(15) + .HasColumnType("character varying(15)"); + + b.Property("ShortName") + .IsRequired() + .HasMaxLength(3) + .HasColumnType("character varying(3)"); + + b.HasKey("Id"); + + b.ToTable("StateTypes"); + }); + + modelBuilder.Entity("ExpressedRealms.DB.UserProfile.PlayerDBModels.Player", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("City") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Phone") + .IsRequired() + .HasMaxLength(15) + .HasColumnType("character varying(15)"); + + b.Property("PlayerNumber") + .HasColumnType("smallint"); + + b.Property("State") + .IsRequired() + .HasMaxLength(2) + .HasColumnType("character varying(2)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Players"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("AccessFailedCount") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Discriminator") + .IsRequired() + .HasMaxLength(13) + .HasColumnType("character varying(13)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("boolean"); + + b.Property("LockoutEnabled") + .HasColumnType("boolean"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("boolean"); + + b.Property("SecurityStamp") + .HasColumnType("text"); + + b.Property("TwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + + b.HasDiscriminator("Discriminator").HasValue("IdentityUser"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("ProviderKey") + .HasColumnType("text"); + + b.Property("ProviderDisplayName") + .HasColumnType("text"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("RoleId") + .HasColumnType("text"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("ExpressedRealms.DB.UserProfile.PlayerDBModels.User", b => + { + b.HasBaseType("Microsoft.AspNetCore.Identity.IdentityUser"); + + b.HasDiscriminator().HasValue("User"); + }); + + modelBuilder.Entity("ExpressedRealms.DB.Characters.Character", b => + { + b.HasOne("ExpressedRealms.DB.Models.Statistics.StatLevel", "AgilityStatLevel") + .WithMany("CharacterAgility") + .HasForeignKey("AgilityId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("ExpressedRealms.DB.Models.Statistics.StatLevel", "ConstitutionStatLevel") + .WithMany("CharacterConstitution") + .HasForeignKey("ConstitutionId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("ExpressedRealms.DB.Models.Statistics.StatLevel", "DexterityStatLevel") + .WithMany("CharacterDexterity") + .HasForeignKey("DexterityId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("ExpressedRealms.DB.Models.Expressions.Expression", "Expression") + .WithMany("Characters") + .HasForeignKey("ExpressionId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("ExpressedRealms.DB.Models.Expressions.ExpressionSection", "FactionInfo") + .WithMany("CharactersList") + .HasForeignKey("FactionId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("ExpressedRealms.DB.Models.Statistics.StatLevel", "IntelligenceStatLevel") + .WithMany("CharacterIntelligence") + .HasForeignKey("IntelligenceId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("ExpressedRealms.DB.UserProfile.PlayerDBModels.Player", "Player") + .WithMany("Characters") + .HasForeignKey("PlayerId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("ExpressedRealms.DB.Models.Statistics.StatLevel", "StrengthStatLevel") + .WithMany("CharacterStrength") + .HasForeignKey("StrengthId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("ExpressedRealms.DB.Models.Statistics.StatLevel", "WillpowerStatLevel") + .WithMany("CharacterWillpower") + .HasForeignKey("WillpowerId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("AgilityStatLevel"); + + b.Navigation("ConstitutionStatLevel"); + + b.Navigation("DexterityStatLevel"); + + b.Navigation("Expression"); + + b.Navigation("FactionInfo"); + + b.Navigation("IntelligenceStatLevel"); + + b.Navigation("Player"); + + b.Navigation("StrengthStatLevel"); + + b.Navigation("WillpowerStatLevel"); + }); + + modelBuilder.Entity("ExpressedRealms.DB.Models.Expressions.ExpressionSection", b => + { + b.HasOne("ExpressedRealms.DB.Models.Expressions.Expression", "Expression") + .WithMany("ExpressionSections") + .HasForeignKey("ExpressionId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("ExpressedRealms.DB.Models.Expressions.ExpressionSection", "Parent") + .WithMany("Children") + .HasForeignKey("ParentId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("ExpressedRealms.DB.Models.Expressions.ExpressionSectionType", "SectionType") + .WithMany("ExpressionSections") + .HasForeignKey("SectionTypeId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Expression"); + + b.Navigation("Parent"); + + b.Navigation("SectionType"); + }); + + modelBuilder.Entity("ExpressedRealms.DB.Models.Skills.CharacterSkillsMapping", b => + { + b.HasOne("ExpressedRealms.DB.Characters.Character", "Character") + .WithMany("CharacterSkillsMappings") + .HasForeignKey("CharacterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("ExpressedRealms.DB.Models.Skills.SkillLevel", "SkillLevel") + .WithMany("CharacterSkillsMappings") + .HasForeignKey("SkillLevelId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("ExpressedRealms.DB.Models.Skills.SkillType", "SkillType") + .WithMany("CharacterSkillsMappings") + .HasForeignKey("SkillTypeId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Character"); + + b.Navigation("SkillLevel"); + + b.Navigation("SkillType"); + }); + + modelBuilder.Entity("ExpressedRealms.DB.Models.Skills.SkillLevelBenefit", b => + { + b.HasOne("ExpressedRealms.DB.Models.Skills.ModifierType", "ModifierType") + .WithMany("SkillLevelBenefits") + .HasForeignKey("ModifierTypeId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("ExpressedRealms.DB.Models.Skills.SkillLevel", "SkillLevel") + .WithMany("SkillLevelBenefits") + .HasForeignKey("SkillLevelId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("ExpressedRealms.DB.Models.Skills.SkillType", "SkillType") + .WithMany("SkillLevelBenefits") + .HasForeignKey("SkillTypeId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("ModifierType"); + + b.Navigation("SkillLevel"); + + b.Navigation("SkillType"); + }); + + modelBuilder.Entity("ExpressedRealms.DB.Models.Skills.SkillType", b => + { + b.HasOne("ExpressedRealms.DB.Models.Skills.SkillSubType", "SkillSubType") + .WithMany("SkillTypes") + .HasForeignKey("SkillSubTypeId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("SkillSubType"); + }); + + modelBuilder.Entity("ExpressedRealms.DB.Models.Statistics.StatDescriptionMapping", b => + { + b.HasOne("ExpressedRealms.DB.Models.Statistics.StatLevel", "StatLevel") + .WithMany("StatDescriptionMappings") + .HasForeignKey("StatLevelId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("ExpressedRealms.DB.Models.Statistics.StatType", "StatType") + .WithMany("StatDescriptionMappings") + .HasForeignKey("StatTypeId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("StatLevel"); + + b.Navigation("StatType"); + }); + + modelBuilder.Entity("ExpressedRealms.DB.UserProfile.PlayerDBModels.Player", b => + { + b.HasOne("ExpressedRealms.DB.UserProfile.PlayerDBModels.User", "User") + .WithOne("Player") + .HasForeignKey("ExpressedRealms.DB.UserProfile.PlayerDBModels.Player", "UserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ExpressedRealms.DB.Characters.Character", b => + { + b.Navigation("CharacterSkillsMappings"); + }); + + modelBuilder.Entity("ExpressedRealms.DB.Models.Expressions.Expression", b => + { + b.Navigation("Characters"); + + b.Navigation("ExpressionSections"); + }); + + modelBuilder.Entity("ExpressedRealms.DB.Models.Expressions.ExpressionSection", b => + { + b.Navigation("CharactersList"); + + b.Navigation("Children"); + }); + + modelBuilder.Entity("ExpressedRealms.DB.Models.Expressions.ExpressionSectionType", b => + { + b.Navigation("ExpressionSections"); + }); + + modelBuilder.Entity("ExpressedRealms.DB.Models.Skills.ModifierType", b => + { + b.Navigation("SkillLevelBenefits"); + }); + + modelBuilder.Entity("ExpressedRealms.DB.Models.Skills.SkillLevel", b => + { + b.Navigation("CharacterSkillsMappings"); + + b.Navigation("SkillLevelBenefits"); + }); + + modelBuilder.Entity("ExpressedRealms.DB.Models.Skills.SkillSubType", b => + { + b.Navigation("SkillTypes"); + }); + + modelBuilder.Entity("ExpressedRealms.DB.Models.Skills.SkillType", b => + { + b.Navigation("CharacterSkillsMappings"); + + b.Navigation("SkillLevelBenefits"); + }); + + modelBuilder.Entity("ExpressedRealms.DB.Models.Statistics.StatLevel", b => + { + b.Navigation("CharacterAgility"); + + b.Navigation("CharacterConstitution"); + + b.Navigation("CharacterDexterity"); + + b.Navigation("CharacterIntelligence"); + + b.Navigation("CharacterStrength"); + + b.Navigation("CharacterWillpower"); + + b.Navigation("StatDescriptionMappings"); + }); + + modelBuilder.Entity("ExpressedRealms.DB.Models.Statistics.StatType", b => + { + b.Navigation("StatDescriptionMappings"); + }); + + modelBuilder.Entity("ExpressedRealms.DB.UserProfile.PlayerDBModels.Player", b => + { + b.Navigation("Characters"); + }); + + modelBuilder.Entity("ExpressedRealms.DB.UserProfile.PlayerDBModels.User", b => + { + b.Navigation("Player") + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/api/ExpressedRealms.DB/Migrations/20240917054709_MakeFactionsOptionalOnCharacter.cs b/api/ExpressedRealms.DB/Migrations/20240917054709_MakeFactionsOptionalOnCharacter.cs new file mode 100644 index 00000000..fd664ca6 --- /dev/null +++ b/api/ExpressedRealms.DB/Migrations/20240917054709_MakeFactionsOptionalOnCharacter.cs @@ -0,0 +1,37 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace ExpressedRealms.DB.Migrations +{ + /// + public partial class MakeFactionsOptionalOnCharacter : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "FactionId", + table: "Characters", + type: "integer", + nullable: true, + oldClrType: typeof(int), + oldType: "integer", + oldDefaultValue: 1); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "FactionId", + table: "Characters", + type: "integer", + nullable: false, + defaultValue: 1, + oldClrType: typeof(int), + oldType: "integer", + oldNullable: true); + } + } +} diff --git a/api/ExpressedRealms.DB/Migrations/ExpressedRealmsDbContextModelSnapshot.cs b/api/ExpressedRealms.DB/Migrations/ExpressedRealmsDbContextModelSnapshot.cs index a6f66855..b7856fcd 100644 --- a/api/ExpressedRealms.DB/Migrations/ExpressedRealmsDbContextModelSnapshot.cs +++ b/api/ExpressedRealms.DB/Migrations/ExpressedRealmsDbContextModelSnapshot.cs @@ -54,10 +54,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("ExpressionId") .HasColumnType("integer"); - b.Property("FactionId") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); + b.Property("FactionId") + .HasColumnType("integer"); b.Property("IntelligenceId") .ValueGeneratedOnAdd() @@ -685,8 +683,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasOne("ExpressedRealms.DB.Models.Expressions.ExpressionSection", "FactionInfo") .WithMany("CharactersList") .HasForeignKey("FactionId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); + .OnDelete(DeleteBehavior.Restrict); b.HasOne("ExpressedRealms.DB.Models.Statistics.StatLevel", "IntelligenceStatLevel") .WithMany("CharacterIntelligence") diff --git a/api/ExpressedRealms.Repositories.Characters/CharacterRepository.cs b/api/ExpressedRealms.Repositories.Characters/CharacterRepository.cs index 1fff375b..550c8e11 100644 --- a/api/ExpressedRealms.Repositories.Characters/CharacterRepository.cs +++ b/api/ExpressedRealms.Repositories.Characters/CharacterRepository.cs @@ -112,25 +112,29 @@ public async Task UpdateCharacterAsync(EditCharacterDto dto) if (character is null) return Result.Fail(new NotFoundFailure("Character")); - var isFaction = await context.ExpressionSections.AnyAsync( - x => - x.ExpressionId == character.ExpressionId - && x.SectionTypeId == (int)ExpressionSectionType.FactionType - && x.Id == dto.FactionId, - cancellationToken - ); - - if (!isFaction) + if (dto.FactionId is not null) { - return Result.Fail( - new FluentValidationFailure( - new Dictionary - { - { "FactionId", ["This is not a valid Faction Id."] } - } - ) + var isFaction = await context.ExpressionSections.AnyAsync( + x => + x.ExpressionId == character.ExpressionId + && x.SectionTypeId == (int)ExpressionSectionType.FactionType + && x.Id == dto.FactionId, + cancellationToken ); + + if (!isFaction) + { + return Result.Fail( + new FluentValidationFailure( + new Dictionary + { + { "FactionId", ["This is not a valid Faction Id."] } + } + ) + ); + } } + character.Name = dto.Name; character.Background = dto.Background; diff --git a/api/ExpressedRealms.Repositories.Characters/DTOs/AddCharacterDto.cs b/api/ExpressedRealms.Repositories.Characters/DTOs/AddCharacterDto.cs index 307a7271..2cd1e394 100644 --- a/api/ExpressedRealms.Repositories.Characters/DTOs/AddCharacterDto.cs +++ b/api/ExpressedRealms.Repositories.Characters/DTOs/AddCharacterDto.cs @@ -5,5 +5,5 @@ public sealed record AddCharacterDto public string Name { get; init; } = null!; public string? Background { get; init; } public int ExpressionId { get; init; } - public int FactionId { get; init; } + public int? FactionId { get; init; } } diff --git a/api/ExpressedRealms.Repositories.Characters/DTOs/AddCharacterDtoValidator.cs b/api/ExpressedRealms.Repositories.Characters/DTOs/AddCharacterDtoValidator.cs index d453dcac..d4910fb2 100644 --- a/api/ExpressedRealms.Repositories.Characters/DTOs/AddCharacterDtoValidator.cs +++ b/api/ExpressedRealms.Repositories.Characters/DTOs/AddCharacterDtoValidator.cs @@ -11,7 +11,6 @@ public AddCharacterDtoValidator(ExpressedRealmsDbContext dbContext) { RuleFor(x => x.Name).NotEmpty().MaximumLength(150); RuleFor(x => x.ExpressionId).NotEmpty(); - RuleFor(x => x.FactionId).NotEmpty(); RuleFor(x => x.ExpressionId) .MustAsync( async (expressionId, cancellationToken) => @@ -36,6 +35,7 @@ public AddCharacterDtoValidator(ExpressedRealmsDbContext dbContext) ); } ) + .When(x => x.FactionId is not null) .WithName(nameof(AddCharacterDto.FactionId)) .WithMessage("This is not a valid Faction Id"); } diff --git a/api/ExpressedRealms.Repositories.Characters/DTOs/EditCharacterDto.cs b/api/ExpressedRealms.Repositories.Characters/DTOs/EditCharacterDto.cs index 5b7de4c4..788c2669 100644 --- a/api/ExpressedRealms.Repositories.Characters/DTOs/EditCharacterDto.cs +++ b/api/ExpressedRealms.Repositories.Characters/DTOs/EditCharacterDto.cs @@ -11,5 +11,5 @@ public sealed record EditCharacterDto public string? Background { get; set; } /// 9 - public int FactionId { get; set; } + public int? FactionId { get; set; } } diff --git a/api/ExpressedRealms.Repositories.Characters/DTOs/EditCharacterDtoValidator.cs b/api/ExpressedRealms.Repositories.Characters/DTOs/EditCharacterDtoValidator.cs index 0ccec72e..c63de09c 100644 --- a/api/ExpressedRealms.Repositories.Characters/DTOs/EditCharacterDtoValidator.cs +++ b/api/ExpressedRealms.Repositories.Characters/DTOs/EditCharacterDtoValidator.cs @@ -8,6 +8,5 @@ public EditCharacterDtoValidator() { RuleFor(x => x.Id).NotEmpty().GreaterThan(0); RuleFor(x => x.Name).NotEmpty().MaximumLength(150); - RuleFor(x => x.FactionId).NotEmpty(); } } diff --git a/api/ExpressedRealms.Repositories.Characters/DTOs/GetEditCharacterDto.cs b/api/ExpressedRealms.Repositories.Characters/DTOs/GetEditCharacterDto.cs index 0c2b7755..6b5777ac 100644 --- a/api/ExpressedRealms.Repositories.Characters/DTOs/GetEditCharacterDto.cs +++ b/api/ExpressedRealms.Repositories.Characters/DTOs/GetEditCharacterDto.cs @@ -5,5 +5,5 @@ public sealed record GetEditCharacterDto public string Name { get; init; } = null!; public string? Background { get; init; } public string Expression { get; init; } = null!; - public int FactionId { get; init; } + public int? FactionId { get; init; } } diff --git a/api/ExpressedRealms.Server/EndPoints/CharacterEndPoints/Requests/CreateCharacterRequest.cs b/api/ExpressedRealms.Server/EndPoints/CharacterEndPoints/Requests/CreateCharacterRequest.cs index 46bc9ee8..0ad9ad9f 100644 --- a/api/ExpressedRealms.Server/EndPoints/CharacterEndPoints/Requests/CreateCharacterRequest.cs +++ b/api/ExpressedRealms.Server/EndPoints/CharacterEndPoints/Requests/CreateCharacterRequest.cs @@ -12,5 +12,5 @@ public record CreateCharacterRequest public int ExpressionId { get; set; } /// 9 - The Shield Wardens - public int FactionId { get; set; } + public int? FactionId { get; set; } } diff --git a/api/ExpressedRealms.Server/EndPoints/CharacterEndPoints/Requests/EditCharacterRequest.cs b/api/ExpressedRealms.Server/EndPoints/CharacterEndPoints/Requests/EditCharacterRequest.cs index c57e9b5e..49485d11 100644 --- a/api/ExpressedRealms.Server/EndPoints/CharacterEndPoints/Requests/EditCharacterRequest.cs +++ b/api/ExpressedRealms.Server/EndPoints/CharacterEndPoints/Requests/EditCharacterRequest.cs @@ -11,5 +11,5 @@ public record EditCharacterRequest public string? Background { get; set; } /// 9 - public int FactionId { get; set; } + public int? FactionId { get; set; } } diff --git a/api/ExpressedRealms.Server/EndPoints/CharacterEndPoints/Responses/CharacterEditResponse.cs b/api/ExpressedRealms.Server/EndPoints/CharacterEndPoints/Responses/CharacterEditResponse.cs index a8627dce..fad97821 100644 --- a/api/ExpressedRealms.Server/EndPoints/CharacterEndPoints/Responses/CharacterEditResponse.cs +++ b/api/ExpressedRealms.Server/EndPoints/CharacterEndPoints/Responses/CharacterEditResponse.cs @@ -22,5 +22,5 @@ public CharacterEditResponse(GetEditCharacterDto dto) public string Expression { get; set; } /// 8 - public int FactionId { get; set; } + public int? FactionId { get; set; } } diff --git a/client/cypress/Components/charcters/character/AddCharacter.cy.ts b/client/cypress/Components/charcters/character/AddCharacter.cy.ts index ca312c3e..f57861f3 100644 --- a/client/cypress/Components/charcters/character/AddCharacter.cy.ts +++ b/client/cypress/Components/charcters/character/AddCharacter.cy.ts @@ -89,7 +89,6 @@ describe('', () => { // Select after selecting, it should now be visable and testable cy.dataCy(faction).should('exist'); cy.dataCy(addCharacterButton).click(); - cy.dataCy(factionHelp).contains("Faction is a required field"); cy.dataCy(faction).click(); cy.get("#faction_list li").each(($ele, i) => { expect($ele).to.have.text(factionValues[i].name) @@ -100,7 +99,6 @@ describe('', () => { cy.dataCy(expression).click(); cy.get("#expression_1").click(); cy.get("@factionOptions2") - cy.dataCy(factionHelp).contains("Faction is a required field"); }) it('Passes Data Through Data To API', () => { diff --git a/client/src/components/characters/character/AddCharacter.vue b/client/src/components/characters/character/AddCharacter.vue index 153fb77b..5c2adf2c 100644 --- a/client/src/components/characters/character/AddCharacter.vue +++ b/client/src/components/characters/character/AddCharacter.vue @@ -18,11 +18,11 @@ const { defineField, handleSubmit, errors } = useForm({ name: string().required() .max(150) .label("Name"), - background: string() + background: string().nullable() .label('Background'), expressionId: object().required() .label("Expression"), - factionId: object().required() + factionId: object().nullable() .label("Faction") }) }); @@ -49,7 +49,7 @@ const onSubmit = handleSubmit((values) => { name: values.name, expressionId: values.expressionId.id, background: values.background, - factionId: values.factionId.id + factionId: values.factionId?.id }) .then(() => { Router.push("/characters"); diff --git a/client/src/components/characters/character/EditCharacter.vue b/client/src/components/characters/character/EditCharacter.vue index 4d019a5d..e3c4d83c 100644 --- a/client/src/components/characters/character/EditCharacter.vue +++ b/client/src/components/characters/character/EditCharacter.vue @@ -45,9 +45,9 @@ const { defineField, handleSubmit, errors } = useForm({ name: string().required() .max(150) .label("Name"), - faction: object().required() + faction: object().nullable() .label('Faction'), - background: string() + background: string().nullable() .label('Background'), }) }); @@ -64,7 +64,7 @@ const onSubmit = handleSubmit((values) => { name: values.name, background: values.background, id: route.params.id, - factionId: values.faction.id + factionId: values.faction?.id }).then(() => { toaster.success("Successfully Updated Character Info!"); });