From 1e108455411f9d0fc49c350007ea60823c34c06d Mon Sep 17 00:00:00 2001 From: Mohammad Saleh Mahdinejad Date: Mon, 9 Sep 2024 13:55:39 +0330 Subject: [PATCH] Refactor. --- .../Controllers/Graph/EdgeControllerTests.cs | 2 +- .../Controllers/Graph/GraphControllerTests.cs | 2 +- .../Controllers/Graph/NodeControllerTests.cs | 2 +- .../Controllers/Panel/AdminControllerTests.cs | 2 +- .../Controllers/Panel/UserControllerTests.cs | 2 +- .../AuthServices/CookieSetterTests.cs | 2 +- .../AuthServices/JwtTokenGeneratorTests.cs | 2 +- .../Graph/GraphSearcherServiceTests.cs | 1 + .../20240909094032_MigrationName.Designer.cs | 437 ++++++++++++++++++ .../20240909094032_MigrationName.cs | 338 ++++++++++++++ RelationshipAnalysis/Program.cs | 107 +---- .../RelationshipAnalysis.csproj | 1 - .../Services/AuthServices/CookieSetter.cs | 2 +- .../AuthServices/JwtTokenGenerator.cs | 2 +- .../Graph/GraphSearcherService.cs | 1 + .../Node/Abstraction/ISearchNodeValidator.cs | 2 +- .../GraphServices/Node/NodeSearchValidator.cs | 1 + .../Authentication/AuthenticationSettings.cs | 42 ++ .../{JWT => Authentication}/JwtSettings.cs | 2 +- .../Settings/DbContext/DbContextExtensions.cs | 15 + .../Settings/Services/ServiceExtensions.cs | 118 +++++ 21 files changed, 971 insertions(+), 112 deletions(-) create mode 100644 RelationshipAnalysis/Migrations/20240909094032_MigrationName.Designer.cs create mode 100644 RelationshipAnalysis/Migrations/20240909094032_MigrationName.cs create mode 100644 RelationshipAnalysis/Settings/Authentication/AuthenticationSettings.cs rename RelationshipAnalysis/Settings/{JWT => Authentication}/JwtSettings.cs (71%) create mode 100644 RelationshipAnalysis/Settings/DbContext/DbContextExtensions.cs create mode 100644 RelationshipAnalysis/Settings/Services/ServiceExtensions.cs diff --git a/RelationshipAnalysis.Integration.Test/Controllers/Graph/EdgeControllerTests.cs b/RelationshipAnalysis.Integration.Test/Controllers/Graph/EdgeControllerTests.cs index df69ca7..78af42f 100644 --- a/RelationshipAnalysis.Integration.Test/Controllers/Graph/EdgeControllerTests.cs +++ b/RelationshipAnalysis.Integration.Test/Controllers/Graph/EdgeControllerTests.cs @@ -7,7 +7,7 @@ using RelationshipAnalysis.Dto.Graph.Edge; using RelationshipAnalysis.Models.Auth; using RelationshipAnalysis.Services.AuthServices; -using RelationshipAnalysis.Settings.JWT; +using RelationshipAnalysis.Settings.Authentication; using JsonSerializer = System.Text.Json.JsonSerializer; namespace RelationshipAnalysis.Integration.Test.Controllers.Graph; diff --git a/RelationshipAnalysis.Integration.Test/Controllers/Graph/GraphControllerTests.cs b/RelationshipAnalysis.Integration.Test/Controllers/Graph/GraphControllerTests.cs index b50c811..8b6eaff 100644 --- a/RelationshipAnalysis.Integration.Test/Controllers/Graph/GraphControllerTests.cs +++ b/RelationshipAnalysis.Integration.Test/Controllers/Graph/GraphControllerTests.cs @@ -9,7 +9,7 @@ using RelationshipAnalysis.Models.Graph.Edge; using RelationshipAnalysis.Models.Graph.Node; using RelationshipAnalysis.Services.AuthServices; -using RelationshipAnalysis.Settings.JWT; +using RelationshipAnalysis.Settings.Authentication; namespace RelationshipAnalysis.Integration.Test.Controllers.Graph; diff --git a/RelationshipAnalysis.Integration.Test/Controllers/Graph/NodeControllerTests.cs b/RelationshipAnalysis.Integration.Test/Controllers/Graph/NodeControllerTests.cs index af19591..ca35e3d 100644 --- a/RelationshipAnalysis.Integration.Test/Controllers/Graph/NodeControllerTests.cs +++ b/RelationshipAnalysis.Integration.Test/Controllers/Graph/NodeControllerTests.cs @@ -10,7 +10,7 @@ using RelationshipAnalysis.Dto.Graph.Node; using RelationshipAnalysis.Models.Auth; using RelationshipAnalysis.Services.AuthServices; -using RelationshipAnalysis.Settings.JWT; +using RelationshipAnalysis.Settings.Authentication; namespace RelationshipAnalysis.Integration.Test.Controllers.Graph; diff --git a/RelationshipAnalysis.Integration.Test/Controllers/Panel/AdminControllerTests.cs b/RelationshipAnalysis.Integration.Test/Controllers/Panel/AdminControllerTests.cs index e53ad75..d1aef4b 100644 --- a/RelationshipAnalysis.Integration.Test/Controllers/Panel/AdminControllerTests.cs +++ b/RelationshipAnalysis.Integration.Test/Controllers/Panel/AdminControllerTests.cs @@ -9,7 +9,7 @@ using RelationshipAnalysis.Dto.Panel.User; using RelationshipAnalysis.Models.Auth; using RelationshipAnalysis.Services.AuthServices; -using RelationshipAnalysis.Settings.JWT; +using RelationshipAnalysis.Settings.Authentication; namespace RelationshipAnalysis.Integration.Test.Controllers.Panel; diff --git a/RelationshipAnalysis.Integration.Test/Controllers/Panel/UserControllerTests.cs b/RelationshipAnalysis.Integration.Test/Controllers/Panel/UserControllerTests.cs index 3e72e26..6006346 100644 --- a/RelationshipAnalysis.Integration.Test/Controllers/Panel/UserControllerTests.cs +++ b/RelationshipAnalysis.Integration.Test/Controllers/Panel/UserControllerTests.cs @@ -8,7 +8,7 @@ using RelationshipAnalysis.Dto.Panel.User; using RelationshipAnalysis.Models.Auth; using RelationshipAnalysis.Services.AuthServices; -using RelationshipAnalysis.Settings.JWT; +using RelationshipAnalysis.Settings.Authentication; namespace RelationshipAnalysis.Integration.Test.Controllers.Panel; diff --git a/RelationshipAnalysis.Test/Services/AuthServices/CookieSetterTests.cs b/RelationshipAnalysis.Test/Services/AuthServices/CookieSetterTests.cs index 7ed14e8..4e9f33c 100644 --- a/RelationshipAnalysis.Test/Services/AuthServices/CookieSetterTests.cs +++ b/RelationshipAnalysis.Test/Services/AuthServices/CookieSetterTests.cs @@ -2,7 +2,7 @@ using Microsoft.Extensions.Options; using Moq; using RelationshipAnalysis.Services.AuthServices; -using RelationshipAnalysis.Settings.JWT; +using RelationshipAnalysis.Settings.Authentication; namespace RelationshipAnalysis.Test.Services.AuthServices; diff --git a/RelationshipAnalysis.Test/Services/AuthServices/JwtTokenGeneratorTests.cs b/RelationshipAnalysis.Test/Services/AuthServices/JwtTokenGeneratorTests.cs index 146dfea..7e840b4 100644 --- a/RelationshipAnalysis.Test/Services/AuthServices/JwtTokenGeneratorTests.cs +++ b/RelationshipAnalysis.Test/Services/AuthServices/JwtTokenGeneratorTests.cs @@ -6,7 +6,7 @@ using Moq; using RelationshipAnalysis.Models.Auth; using RelationshipAnalysis.Services.AuthServices; -using RelationshipAnalysis.Settings.JWT; +using RelationshipAnalysis.Settings.Authentication; namespace RelationshipAnalysis.Test.Services.AuthServices; diff --git a/RelationshipAnalysis.Test/Services/GraphServices/Graph/GraphSearcherServiceTests.cs b/RelationshipAnalysis.Test/Services/GraphServices/Graph/GraphSearcherServiceTests.cs index 940d85c..5c9d45f 100644 --- a/RelationshipAnalysis.Test/Services/GraphServices/Graph/GraphSearcherServiceTests.cs +++ b/RelationshipAnalysis.Test/Services/GraphServices/Graph/GraphSearcherServiceTests.cs @@ -11,6 +11,7 @@ using RelationshipAnalysis.Services.GraphServices.Abstraction; using RelationshipAnalysis.Services.GraphServices.Edge.Abstraction; using RelationshipAnalysis.Services.GraphServices.Graph.Abstraction; +using RelationshipAnalysis.Services.GraphServices.Node.Abstraction; namespace RelationshipAnalysis.Test.Services.GraphServices.Graph { diff --git a/RelationshipAnalysis/Migrations/20240909094032_MigrationName.Designer.cs b/RelationshipAnalysis/Migrations/20240909094032_MigrationName.Designer.cs new file mode 100644 index 0000000..fd460f3 --- /dev/null +++ b/RelationshipAnalysis/Migrations/20240909094032_MigrationName.Designer.cs @@ -0,0 +1,437 @@ +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using RelationshipAnalysis.Context; + +#nullable disable + +namespace RelationshipAnalysis.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20240909094032_MigrationName")] + partial class MigrationName + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.8") + .HasAnnotation("Proxies:ChangeTracking", false) + .HasAnnotation("Proxies:CheckEquality", false) + .HasAnnotation("Proxies:LazyLoading", true) + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("RelationshipAnalysis.Models.Auth.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Permissions") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Roles"); + }); + + modelBuilder.Entity("RelationshipAnalysis.Models.Auth.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Email") + .IsRequired() + .HasColumnType("text"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("text"); + + b.Property("PasswordHash") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Id"); + + b.HasIndex("Email") + .IsUnique(); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("RelationshipAnalysis.Models.Auth.UserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("RoleId") + .HasColumnType("integer"); + + b.Property("UserId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.HasIndex("UserId", "RoleId") + .IsUnique(); + + b.ToTable("UserRoles"); + }); + + modelBuilder.Entity("RelationshipAnalysis.Models.Graph.Edge.Edge", b => + { + b.Property("EdgeId") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("EdgeId")); + + b.Property("EdgeCategoryId") + .HasColumnType("integer"); + + b.Property("EdgeDestinationNodeId") + .HasColumnType("integer"); + + b.Property("EdgeSourceNodeId") + .HasColumnType("integer"); + + b.Property("EdgeUniqueString") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("EdgeId"); + + b.HasIndex("EdgeCategoryId"); + + b.HasIndex("EdgeDestinationNodeId"); + + b.HasIndex("EdgeSourceNodeId"); + + b.ToTable("Edges"); + }); + + modelBuilder.Entity("RelationshipAnalysis.Models.Graph.Edge.EdgeAttribute", b => + { + b.Property("EdgeAttributeId") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("EdgeAttributeId")); + + b.Property("EdgeAttributeName") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("EdgeAttributeId"); + + b.ToTable("EdgeAttributes"); + }); + + modelBuilder.Entity("RelationshipAnalysis.Models.Graph.Edge.EdgeCategory", b => + { + b.Property("EdgeCategoryId") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("EdgeCategoryId")); + + b.Property("EdgeCategoryName") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("EdgeCategoryId"); + + b.ToTable("EdgeCategories"); + }); + + modelBuilder.Entity("RelationshipAnalysis.Models.Graph.Edge.EdgeValue", b => + { + b.Property("ValueId") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ValueId")); + + b.Property("EdgeAttributeId") + .HasColumnType("integer"); + + b.Property("EdgeId") + .HasColumnType("integer"); + + b.Property("ValueData") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("ValueId"); + + b.HasIndex("EdgeAttributeId"); + + b.HasIndex("EdgeId"); + + b.ToTable("EdgeValues"); + }); + + modelBuilder.Entity("RelationshipAnalysis.Models.Graph.Node.Node", b => + { + b.Property("NodeId") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("NodeId")); + + b.Property("NodeCategoryId") + .HasColumnType("integer"); + + b.Property("NodeUniqueString") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("NodeId"); + + b.HasIndex("NodeCategoryId"); + + b.ToTable("Nodes"); + }); + + modelBuilder.Entity("RelationshipAnalysis.Models.Graph.Node.NodeAttribute", b => + { + b.Property("NodeAttributeId") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("NodeAttributeId")); + + b.Property("NodeAttributeName") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("NodeAttributeId"); + + b.ToTable("NodeAttributes"); + }); + + modelBuilder.Entity("RelationshipAnalysis.Models.Graph.Node.NodeCategory", b => + { + b.Property("NodeCategoryId") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("NodeCategoryId")); + + b.Property("NodeCategoryName") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("NodeCategoryId"); + + b.ToTable("NodeCategories"); + }); + + modelBuilder.Entity("RelationshipAnalysis.Models.Graph.Node.NodeValue", b => + { + b.Property("ValueId") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ValueId")); + + b.Property("NodeAttributeId") + .HasColumnType("integer"); + + b.Property("NodeId") + .HasColumnType("integer"); + + b.Property("ValueData") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("ValueId"); + + b.HasIndex("NodeAttributeId"); + + b.HasIndex("NodeId"); + + b.ToTable("NodeValues"); + }); + + modelBuilder.Entity("RelationshipAnalysis.Models.Auth.UserRole", b => + { + b.HasOne("RelationshipAnalysis.Models.Auth.Role", "Role") + .WithMany("UserRoles") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RelationshipAnalysis.Models.Auth.User", "User") + .WithMany("UserRoles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("RelationshipAnalysis.Models.Graph.Edge.Edge", b => + { + b.HasOne("RelationshipAnalysis.Models.Graph.Edge.EdgeCategory", "EdgeCategory") + .WithMany("Edges") + .HasForeignKey("EdgeCategoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RelationshipAnalysis.Models.Graph.Node.Node", "NodeDestination") + .WithMany("DestinationEdges") + .HasForeignKey("EdgeDestinationNodeId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("RelationshipAnalysis.Models.Graph.Node.Node", "NodeSource") + .WithMany("SourceEdges") + .HasForeignKey("EdgeSourceNodeId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("EdgeCategory"); + + b.Navigation("NodeDestination"); + + b.Navigation("NodeSource"); + }); + + modelBuilder.Entity("RelationshipAnalysis.Models.Graph.Edge.EdgeValue", b => + { + b.HasOne("RelationshipAnalysis.Models.Graph.Edge.EdgeAttribute", "EdgeAttribute") + .WithMany("EdgeValues") + .HasForeignKey("EdgeAttributeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RelationshipAnalysis.Models.Graph.Edge.Edge", "Edge") + .WithMany("EdgeValues") + .HasForeignKey("EdgeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Edge"); + + b.Navigation("EdgeAttribute"); + }); + + modelBuilder.Entity("RelationshipAnalysis.Models.Graph.Node.Node", b => + { + b.HasOne("RelationshipAnalysis.Models.Graph.Node.NodeCategory", "NodeCategory") + .WithMany("Nodes") + .HasForeignKey("NodeCategoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("NodeCategory"); + }); + + modelBuilder.Entity("RelationshipAnalysis.Models.Graph.Node.NodeValue", b => + { + b.HasOne("RelationshipAnalysis.Models.Graph.Node.NodeAttribute", "NodeAttribute") + .WithMany("Values") + .HasForeignKey("NodeAttributeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RelationshipAnalysis.Models.Graph.Node.Node", "Node") + .WithMany("Values") + .HasForeignKey("NodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Node"); + + b.Navigation("NodeAttribute"); + }); + + modelBuilder.Entity("RelationshipAnalysis.Models.Auth.Role", b => + { + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("RelationshipAnalysis.Models.Auth.User", b => + { + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("RelationshipAnalysis.Models.Graph.Edge.Edge", b => + { + b.Navigation("EdgeValues"); + }); + + modelBuilder.Entity("RelationshipAnalysis.Models.Graph.Edge.EdgeAttribute", b => + { + b.Navigation("EdgeValues"); + }); + + modelBuilder.Entity("RelationshipAnalysis.Models.Graph.Edge.EdgeCategory", b => + { + b.Navigation("Edges"); + }); + + modelBuilder.Entity("RelationshipAnalysis.Models.Graph.Node.Node", b => + { + b.Navigation("DestinationEdges"); + + b.Navigation("SourceEdges"); + + b.Navigation("Values"); + }); + + modelBuilder.Entity("RelationshipAnalysis.Models.Graph.Node.NodeAttribute", b => + { + b.Navigation("Values"); + }); + + modelBuilder.Entity("RelationshipAnalysis.Models.Graph.Node.NodeCategory", b => + { + b.Navigation("Nodes"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/RelationshipAnalysis/Migrations/20240909094032_MigrationName.cs b/RelationshipAnalysis/Migrations/20240909094032_MigrationName.cs new file mode 100644 index 0000000..7be582f --- /dev/null +++ b/RelationshipAnalysis/Migrations/20240909094032_MigrationName.cs @@ -0,0 +1,338 @@ +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace RelationshipAnalysis.Migrations +{ + /// + public partial class MigrationName : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "EdgeAttributes", + columns: table => new + { + EdgeAttributeId = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + EdgeAttributeName = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_EdgeAttributes", x => x.EdgeAttributeId); + }); + + migrationBuilder.CreateTable( + name: "EdgeCategories", + columns: table => new + { + EdgeCategoryId = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + EdgeCategoryName = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_EdgeCategories", x => x.EdgeCategoryId); + }); + + migrationBuilder.CreateTable( + name: "NodeAttributes", + columns: table => new + { + NodeAttributeId = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + NodeAttributeName = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_NodeAttributes", x => x.NodeAttributeId); + }); + + migrationBuilder.CreateTable( + name: "NodeCategories", + columns: table => new + { + NodeCategoryId = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + NodeCategoryName = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_NodeCategories", x => x.NodeCategoryId); + }); + + migrationBuilder.CreateTable( + name: "Roles", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Name = table.Column(type: "character varying(50)", maxLength: 50, nullable: false), + Permissions = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Roles", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Users", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Username = table.Column(type: "character varying(50)", maxLength: 50, nullable: false), + PasswordHash = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + FirstName = table.Column(type: "text", nullable: false), + LastName = table.Column(type: "text", nullable: false), + Email = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Users", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Nodes", + columns: table => new + { + NodeId = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + NodeUniqueString = table.Column(type: "text", nullable: false), + NodeCategoryId = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Nodes", x => x.NodeId); + table.ForeignKey( + name: "FK_Nodes_NodeCategories_NodeCategoryId", + column: x => x.NodeCategoryId, + principalTable: "NodeCategories", + principalColumn: "NodeCategoryId", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "UserRoles", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + UserId = table.Column(type: "integer", nullable: false), + RoleId = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_UserRoles", x => x.Id); + table.ForeignKey( + name: "FK_UserRoles_Roles_RoleId", + column: x => x.RoleId, + principalTable: "Roles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_UserRoles_Users_UserId", + column: x => x.UserId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Edges", + columns: table => new + { + EdgeId = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + EdgeSourceNodeId = table.Column(type: "integer", nullable: false), + EdgeDestinationNodeId = table.Column(type: "integer", nullable: false), + EdgeCategoryId = table.Column(type: "integer", nullable: false), + EdgeUniqueString = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Edges", x => x.EdgeId); + table.ForeignKey( + name: "FK_Edges_EdgeCategories_EdgeCategoryId", + column: x => x.EdgeCategoryId, + principalTable: "EdgeCategories", + principalColumn: "EdgeCategoryId", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_Edges_Nodes_EdgeDestinationNodeId", + column: x => x.EdgeDestinationNodeId, + principalTable: "Nodes", + principalColumn: "NodeId", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_Edges_Nodes_EdgeSourceNodeId", + column: x => x.EdgeSourceNodeId, + principalTable: "Nodes", + principalColumn: "NodeId", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "NodeValues", + columns: table => new + { + ValueId = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + NodeId = table.Column(type: "integer", nullable: false), + NodeAttributeId = table.Column(type: "integer", nullable: false), + ValueData = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_NodeValues", x => x.ValueId); + table.ForeignKey( + name: "FK_NodeValues_NodeAttributes_NodeAttributeId", + column: x => x.NodeAttributeId, + principalTable: "NodeAttributes", + principalColumn: "NodeAttributeId", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_NodeValues_Nodes_NodeId", + column: x => x.NodeId, + principalTable: "Nodes", + principalColumn: "NodeId", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "EdgeValues", + columns: table => new + { + ValueId = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + EdgeId = table.Column(type: "integer", nullable: false), + EdgeAttributeId = table.Column(type: "integer", nullable: false), + ValueData = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_EdgeValues", x => x.ValueId); + table.ForeignKey( + name: "FK_EdgeValues_EdgeAttributes_EdgeAttributeId", + column: x => x.EdgeAttributeId, + principalTable: "EdgeAttributes", + principalColumn: "EdgeAttributeId", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_EdgeValues_Edges_EdgeId", + column: x => x.EdgeId, + principalTable: "Edges", + principalColumn: "EdgeId", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_Edges_EdgeCategoryId", + table: "Edges", + column: "EdgeCategoryId"); + + migrationBuilder.CreateIndex( + name: "IX_Edges_EdgeDestinationNodeId", + table: "Edges", + column: "EdgeDestinationNodeId"); + + migrationBuilder.CreateIndex( + name: "IX_Edges_EdgeSourceNodeId", + table: "Edges", + column: "EdgeSourceNodeId"); + + migrationBuilder.CreateIndex( + name: "IX_EdgeValues_EdgeAttributeId", + table: "EdgeValues", + column: "EdgeAttributeId"); + + migrationBuilder.CreateIndex( + name: "IX_EdgeValues_EdgeId", + table: "EdgeValues", + column: "EdgeId"); + + migrationBuilder.CreateIndex( + name: "IX_Nodes_NodeCategoryId", + table: "Nodes", + column: "NodeCategoryId"); + + migrationBuilder.CreateIndex( + name: "IX_NodeValues_NodeAttributeId", + table: "NodeValues", + column: "NodeAttributeId"); + + migrationBuilder.CreateIndex( + name: "IX_NodeValues_NodeId", + table: "NodeValues", + column: "NodeId"); + + migrationBuilder.CreateIndex( + name: "IX_Roles_Name", + table: "Roles", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_UserRoles_RoleId", + table: "UserRoles", + column: "RoleId"); + + migrationBuilder.CreateIndex( + name: "IX_UserRoles_UserId_RoleId", + table: "UserRoles", + columns: new[] { "UserId", "RoleId" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Users_Email", + table: "Users", + column: "Email", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Users_Username", + table: "Users", + column: "Username", + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "EdgeValues"); + + migrationBuilder.DropTable( + name: "NodeValues"); + + migrationBuilder.DropTable( + name: "UserRoles"); + + migrationBuilder.DropTable( + name: "EdgeAttributes"); + + migrationBuilder.DropTable( + name: "Edges"); + + migrationBuilder.DropTable( + name: "NodeAttributes"); + + migrationBuilder.DropTable( + name: "Roles"); + + migrationBuilder.DropTable( + name: "Users"); + + migrationBuilder.DropTable( + name: "EdgeCategories"); + + migrationBuilder.DropTable( + name: "Nodes"); + + migrationBuilder.DropTable( + name: "NodeCategories"); + } + } +} diff --git a/RelationshipAnalysis/Program.cs b/RelationshipAnalysis/Program.cs index 27cd9bb..4e9ce4c 100644 --- a/RelationshipAnalysis/Program.cs +++ b/RelationshipAnalysis/Program.cs @@ -42,7 +42,9 @@ using RelationshipAnalysis.Services.Panel.UserPanelServices.UserUpdateInfoService.Abstraction; using RelationshipAnalysis.Services.Panel.UserPanelServices.UserUpdatePasswordService; using RelationshipAnalysis.Services.Panel.UserPanelServices.UserUpdatePasswordService.Abstraction; -using RelationshipAnalysis.Settings.JWT; +using RelationshipAnalysis.Settings.Authentication; +using RelationshipAnalysis.Settings.DbContext; +using RelationshipAnalysis.Settings.Services; using EdgeAttributesReceiver = RelationshipAnalysis.Services.GraphServices.Edge.EdgeAttributesReceiver; using NodeAttributesReceiver = RelationshipAnalysis.Services.GraphServices.Node.NodeAttributesReceiver; @@ -53,111 +55,16 @@ builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); -builder.Services.AddDbContext(options => - options.UseNpgsql(builder.Configuration["CONNECTION_STRING"]).UseLazyLoadingProxies()); -builder.Services.AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddKeyedSingleton("node") - .AddKeyedSingleton("edge") - .AddKeyedSingleton("node") - .AddKeyedSingleton("edge") - .AddKeyedSingleton("node") - .AddKeyedSingleton("edge"); + +builder.Services.AddApplicationDbContext(builder.Configuration); +builder.Services.AddCustomServices(); builder.Services.Configure(builder.Configuration.GetSection("Jwt")); builder.Services.AddAutoMapper(typeof(UserUpdateInfoMapper)); -builder.Services.AddAuthentication(options => - { - options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; - options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; - }) - .AddJwtBearer(options => - { - var jwtSettings = builder.Configuration.GetSection("Jwt").Get(); - options.TokenValidationParameters = new TokenValidationParameters - { - ValidateLifetime = true, - ValidateIssuerSigningKey = true, - ValidateIssuer = false, - ValidateAudience = false, - IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.Key)) - }; - - options.Events = new JwtBearerEvents - { - OnMessageReceived = context => - { - var cookie = context.Request.Cookies[jwtSettings.CookieName]; - if (!string.IsNullOrEmpty(cookie)) context.Token = cookie; - return Task.CompletedTask; - } - }; - }); - +builder.Services.AddJwtAuthentication(builder.Configuration); var app = builder.Build(); if (app.Environment.IsDevelopment()) diff --git a/RelationshipAnalysis/RelationshipAnalysis.csproj b/RelationshipAnalysis/RelationshipAnalysis.csproj index 24b75e9..d34b44f 100644 --- a/RelationshipAnalysis/RelationshipAnalysis.csproj +++ b/RelationshipAnalysis/RelationshipAnalysis.csproj @@ -27,6 +27,5 @@ - \ No newline at end of file diff --git a/RelationshipAnalysis/Services/AuthServices/CookieSetter.cs b/RelationshipAnalysis/Services/AuthServices/CookieSetter.cs index 6e6987b..6c33156 100644 --- a/RelationshipAnalysis/Services/AuthServices/CookieSetter.cs +++ b/RelationshipAnalysis/Services/AuthServices/CookieSetter.cs @@ -1,6 +1,6 @@ using Microsoft.Extensions.Options; using RelationshipAnalysis.Services.AuthServices.Abstraction; -using RelationshipAnalysis.Settings.JWT; +using RelationshipAnalysis.Settings.Authentication; namespace RelationshipAnalysis.Services.AuthServices; diff --git a/RelationshipAnalysis/Services/AuthServices/JwtTokenGenerator.cs b/RelationshipAnalysis/Services/AuthServices/JwtTokenGenerator.cs index a9da7e6..5246a0c 100644 --- a/RelationshipAnalysis/Services/AuthServices/JwtTokenGenerator.cs +++ b/RelationshipAnalysis/Services/AuthServices/JwtTokenGenerator.cs @@ -5,7 +5,7 @@ using Microsoft.IdentityModel.Tokens; using RelationshipAnalysis.Models.Auth; using RelationshipAnalysis.Services.AuthServices.Abstraction; -using RelationshipAnalysis.Settings.JWT; +using RelationshipAnalysis.Settings.Authentication; namespace RelationshipAnalysis.Services.AuthServices; diff --git a/RelationshipAnalysis/Services/GraphServices/Graph/GraphSearcherService.cs b/RelationshipAnalysis/Services/GraphServices/Graph/GraphSearcherService.cs index 95dce57..de97101 100644 --- a/RelationshipAnalysis/Services/GraphServices/Graph/GraphSearcherService.cs +++ b/RelationshipAnalysis/Services/GraphServices/Graph/GraphSearcherService.cs @@ -5,6 +5,7 @@ using RelationshipAnalysis.Services.GraphServices.Abstraction; using RelationshipAnalysis.Services.GraphServices.Edge.Abstraction; using RelationshipAnalysis.Services.GraphServices.Graph.Abstraction; +using RelationshipAnalysis.Services.GraphServices.Node.Abstraction; using ApplicationDbContext = RelationshipAnalysis.Context.ApplicationDbContext; namespace RelationshipAnalysis.Services.GraphServices.Graph diff --git a/RelationshipAnalysis/Services/GraphServices/Node/Abstraction/ISearchNodeValidator.cs b/RelationshipAnalysis/Services/GraphServices/Node/Abstraction/ISearchNodeValidator.cs index a4cc4ce..b32d265 100644 --- a/RelationshipAnalysis/Services/GraphServices/Node/Abstraction/ISearchNodeValidator.cs +++ b/RelationshipAnalysis/Services/GraphServices/Node/Abstraction/ISearchNodeValidator.cs @@ -1,4 +1,4 @@ -namespace RelationshipAnalysis.Services.GraphServices.Abstraction; +namespace RelationshipAnalysis.Services.GraphServices.Node.Abstraction; public interface ISearchNodeValidator { diff --git a/RelationshipAnalysis/Services/GraphServices/Node/NodeSearchValidator.cs b/RelationshipAnalysis/Services/GraphServices/Node/NodeSearchValidator.cs index 4d9a419..c7c6b76 100644 --- a/RelationshipAnalysis/Services/GraphServices/Node/NodeSearchValidator.cs +++ b/RelationshipAnalysis/Services/GraphServices/Node/NodeSearchValidator.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore; using RelationshipAnalysis.Context; using RelationshipAnalysis.Services.GraphServices.Abstraction; +using RelationshipAnalysis.Services.GraphServices.Node.Abstraction; namespace RelationshipAnalysis.Services.GraphServices.Node; diff --git a/RelationshipAnalysis/Settings/Authentication/AuthenticationSettings.cs b/RelationshipAnalysis/Settings/Authentication/AuthenticationSettings.cs new file mode 100644 index 0000000..df0e2b3 --- /dev/null +++ b/RelationshipAnalysis/Settings/Authentication/AuthenticationSettings.cs @@ -0,0 +1,42 @@ +using System.Text; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.IdentityModel.Tokens; + +namespace RelationshipAnalysis.Settings.Authentication; + +public static class AuthenticationExtensions +{ + public static IServiceCollection AddJwtAuthentication(this IServiceCollection services, IConfiguration configuration) + { + var jwtSettings = configuration.GetSection("Jwt").Get(); + + services.AddAuthentication(options => + { + options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + }) + .AddJwtBearer(options => + { + options.TokenValidationParameters = new TokenValidationParameters + { + ValidateLifetime = true, + ValidateIssuerSigningKey = true, + ValidateIssuer = false, + ValidateAudience = false, + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.Key)) + }; + + options.Events = new JwtBearerEvents + { + OnMessageReceived = context => + { + var cookie = context.Request.Cookies[jwtSettings.CookieName]; + if (!string.IsNullOrEmpty(cookie)) context.Token = cookie; + return Task.CompletedTask; + } + }; + }); + + return services; + } +} \ No newline at end of file diff --git a/RelationshipAnalysis/Settings/JWT/JwtSettings.cs b/RelationshipAnalysis/Settings/Authentication/JwtSettings.cs similarity index 71% rename from RelationshipAnalysis/Settings/JWT/JwtSettings.cs rename to RelationshipAnalysis/Settings/Authentication/JwtSettings.cs index d34e4c0..9297a41 100644 --- a/RelationshipAnalysis/Settings/JWT/JwtSettings.cs +++ b/RelationshipAnalysis/Settings/Authentication/JwtSettings.cs @@ -1,4 +1,4 @@ -namespace RelationshipAnalysis.Settings.JWT; +namespace RelationshipAnalysis.Settings.Authentication; public class JwtSettings { diff --git a/RelationshipAnalysis/Settings/DbContext/DbContextExtensions.cs b/RelationshipAnalysis/Settings/DbContext/DbContextExtensions.cs new file mode 100644 index 0000000..6fbb64e --- /dev/null +++ b/RelationshipAnalysis/Settings/DbContext/DbContextExtensions.cs @@ -0,0 +1,15 @@ +using Microsoft.EntityFrameworkCore; +using RelationshipAnalysis.Context; + +namespace RelationshipAnalysis.Settings.DbContext; + +public static class DbContextExtensions +{ + public static IServiceCollection AddApplicationDbContext(this IServiceCollection services, IConfiguration configuration) + { + services.AddDbContext(options => + options.UseNpgsql(configuration["CONNECTION_STRING"]).UseLazyLoadingProxies()); + + return services; + } +} \ No newline at end of file diff --git a/RelationshipAnalysis/Settings/Services/ServiceExtensions.cs b/RelationshipAnalysis/Settings/Services/ServiceExtensions.cs new file mode 100644 index 0000000..506bac6 --- /dev/null +++ b/RelationshipAnalysis/Settings/Services/ServiceExtensions.cs @@ -0,0 +1,118 @@ +using RelationshipAnalysis.Services; +using RelationshipAnalysis.Services.Abstraction; +using RelationshipAnalysis.Services.AuthServices; +using RelationshipAnalysis.Services.AuthServices.Abstraction; +using RelationshipAnalysis.Services.CRUD.Permissions; +using RelationshipAnalysis.Services.CRUD.Permissions.Abstraction; +using RelationshipAnalysis.Services.CRUD.Role; +using RelationshipAnalysis.Services.CRUD.Role.Abstraction; +using RelationshipAnalysis.Services.CRUD.User; +using RelationshipAnalysis.Services.CRUD.User.Abstraction; +using RelationshipAnalysis.Services.CRUD.UserRole; +using RelationshipAnalysis.Services.CRUD.UserRole.Abstraction; +using RelationshipAnalysis.Services.GraphServices; +using RelationshipAnalysis.Services.GraphServices.Abstraction; +using RelationshipAnalysis.Services.GraphServices.Edge; +using RelationshipAnalysis.Services.GraphServices.Edge.Abstraction; +using RelationshipAnalysis.Services.GraphServices.Graph; +using RelationshipAnalysis.Services.GraphServices.Graph.Abstraction; +using RelationshipAnalysis.Services.GraphServices.Node; +using RelationshipAnalysis.Services.GraphServices.Node.Abstraction; +using RelationshipAnalysis.Services.Panel.AdminPanelServices.AllUserService; +using RelationshipAnalysis.Services.Panel.AdminPanelServices.AllUserService.Abstraction; +using RelationshipAnalysis.Services.Panel.AdminPanelServices.CreateUserService; +using RelationshipAnalysis.Services.Panel.AdminPanelServices.CreateUserService.Abstraction; +using RelationshipAnalysis.Services.Panel.AdminPanelServices.UserDeleteService; +using RelationshipAnalysis.Services.Panel.AdminPanelServices.UserDeleteService.Abstraction; +using RelationshipAnalysis.Services.Panel.AdminPanelServices.UserUpdateRolesService; +using RelationshipAnalysis.Services.Panel.AdminPanelServices.UserUpdateRolesService.Abstraction; +using RelationshipAnalysis.Services.Panel.UserPanelServices.LogoutService; +using RelationshipAnalysis.Services.Panel.UserPanelServices.LogoutService.Abstraction; +using RelationshipAnalysis.Services.Panel.UserPanelServices.PermissionsService; +using RelationshipAnalysis.Services.Panel.UserPanelServices.PermissionsService.Abstraction; +using RelationshipAnalysis.Services.Panel.UserPanelServices.UserInfoService; +using RelationshipAnalysis.Services.Panel.UserPanelServices.UserInfoService.Abstraction; +using RelationshipAnalysis.Services.Panel.UserPanelServices.UserUpdateInfoService; +using RelationshipAnalysis.Services.Panel.UserPanelServices.UserUpdateInfoService.Abstraction; +using RelationshipAnalysis.Services.Panel.UserPanelServices.UserUpdatePasswordService; +using RelationshipAnalysis.Services.Panel.UserPanelServices.UserUpdatePasswordService.Abstraction; + +namespace RelationshipAnalysis.Settings.Services; + +public static class ServiceExtensions +{ + public static IServiceCollection AddCustomServices(this IServiceCollection services) + { + services.AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddKeyedSingleton("node") + .AddKeyedSingleton("edge") + .AddKeyedSingleton("node") + .AddKeyedSingleton("edge") + .AddKeyedSingleton("node") + .AddKeyedSingleton("edge"); + + return services; + } +} \ No newline at end of file