diff --git a/Server/Constants/Identity.cs b/Server/Constants/Identity.cs index a13f66e..80b0f68 100644 --- a/Server/Constants/Identity.cs +++ b/Server/Constants/Identity.cs @@ -10,8 +10,7 @@ public class Identity Administrator } - public const string DefaultUsername = "admin"; public const string DefaultEmail = "admin@subdomain.domain"; public const string DefaultPassword = "123qwe!@#QWE"; public const Roles DefaultRole = Roles.Administrator; -} +} \ No newline at end of file diff --git a/Server/Data/ApplicationDbContext.cs b/Server/Data/ApplicationDbContext.cs index 9aa37e6..b097adf 100644 --- a/Server/Data/ApplicationDbContext.cs +++ b/Server/Data/ApplicationDbContext.cs @@ -12,7 +12,11 @@ public class ApplicationDbContext : IdentityDbContext { Database.EnsureCreated(); } - + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + modelBuilder.Entity().Ignore(u => u.UserName).Ignore(u => u.NormalizedUserName); + } public DbSet Companies { get; set; } = null!; public DbSet Vehicles { get; set; } = null!; public DbSet VehicleEnrollments { get; set; } = null!; diff --git a/Server/Data/SeedData.cs b/Server/Data/SeedData.cs index 9350b28..420a939 100644 --- a/Server/Data/SeedData.cs +++ b/Server/Data/SeedData.cs @@ -19,7 +19,6 @@ public class SeedData //Seed Default User var defaultUser = new User { - UserName = Constants.Identity.DefaultUsername, Email = Constants.Identity.DefaultEmail, EmailConfirmed = true }; diff --git a/Server/Migrations/20230426081251_Remove_UserName_and_NormalizedUserName_From_AspNetUsers.Designer.cs b/Server/Migrations/20230426081251_Remove_UserName_and_NormalizedUserName_From_AspNetUsers.Designer.cs new file mode 100644 index 0000000..c2d38ed --- /dev/null +++ b/Server/Migrations/20230426081251_Remove_UserName_and_NormalizedUserName_From_AspNetUsers.Designer.cs @@ -0,0 +1,906 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using Server.Data; + +#nullable disable + +namespace Server.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20230426081251_Remove_UserName_and_NormalizedUserName_From_AspNetUsers")] + partial class Remove_UserName_and_NormalizedUserName_From_AspNetUsers + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.9") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + 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.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("Server.Models.Address", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CityId") + .HasColumnType("integer"); + + b.Property("Latitude") + .HasColumnType("double precision"); + + b.Property("Longitude") + .HasColumnType("double precision"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("CityId"); + + b.ToTable("Addresses"); + }); + + modelBuilder.Entity("Server.Models.City", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("StateId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("StateId"); + + b.ToTable("Cities"); + }); + + modelBuilder.Entity("Server.Models.Company", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OwnerId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("OwnerId"); + + b.ToTable("Companies"); + }); + + modelBuilder.Entity("Server.Models.Country", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Code") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Countries"); + }); + + modelBuilder.Entity("Server.Models.Review", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Comment") + .HasColumnType("text"); + + b.Property("PostDateTimeUtc") + .HasColumnType("timestamp with time zone"); + + b.Property("Rating") + .HasColumnType("integer"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.Property("VehicleEnrollmentId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.HasIndex("VehicleEnrollmentId"); + + b.ToTable("Reviews"); + }); + + modelBuilder.Entity("Server.Models.Route", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Routes"); + }); + + modelBuilder.Entity("Server.Models.RouteAddress", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AddressId") + .HasColumnType("integer"); + + b.Property("Order") + .HasColumnType("integer"); + + b.Property("RouteAddressDetailsId") + .HasColumnType("integer"); + + b.Property("RouteId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("AddressId"); + + b.HasIndex("RouteId"); + + b.ToTable("RouteAddresses"); + }); + + modelBuilder.Entity("Server.Models.RouteAddressDetails", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CostToNextCity") + .HasColumnType("double precision"); + + b.Property("RouteAddressId") + .HasColumnType("integer"); + + b.Property("TimeSpanToNextCity") + .HasColumnType("interval"); + + b.Property("VehicleEnrollmentId") + .HasColumnType("integer"); + + b.Property("WaitTimeSpan") + .HasColumnType("interval"); + + b.HasKey("Id"); + + b.HasIndex("RouteAddressId"); + + b.HasIndex("VehicleEnrollmentId"); + + b.ToTable("RouteAddressDetails"); + }); + + modelBuilder.Entity("Server.Models.State", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CountryId") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("CountryId"); + + b.ToTable("States"); + }); + + modelBuilder.Entity("Server.Models.Ticket", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("FirstRouteAddressId") + .HasColumnType("integer"); + + b.Property("IsMissed") + .HasColumnType("boolean"); + + b.Property("IsReturned") + .HasColumnType("boolean"); + + b.Property("LastRouteAddressId") + .HasColumnType("integer"); + + b.Property("PurchaseDateTimeUtc") + .HasColumnType("timestamp with time zone"); + + b.Property("TicketGroupId") + .HasColumnType("integer"); + + b.Property("VehicleEnrollmentId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("TicketGroupId"); + + b.HasIndex("VehicleEnrollmentId"); + + b.ToTable("Tickets"); + }); + + modelBuilder.Entity("Server.Models.TicketGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("TicketGroups"); + }); + + modelBuilder.Entity("Server.Models.User", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("AccessFailedCount") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("boolean"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("text"); + + b.Property("LockoutEnabled") + .HasColumnType("boolean"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("Patronymic") + .IsRequired() + .HasColumnType("text"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("boolean"); + + b.Property("SecurityStamp") + .HasColumnType("text"); + + b.Property("TwoFactorEnabled") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("Server.Models.Vehicle", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Capacity") + .HasColumnType("integer"); + + b.Property("CompanyId") + .HasColumnType("integer"); + + b.Property("HasBelts") + .HasColumnType("boolean"); + + b.Property("HasClimateControl") + .HasColumnType("boolean"); + + b.Property("HasOutlet") + .HasColumnType("boolean"); + + b.Property("HasStewardess") + .HasColumnType("boolean"); + + b.Property("HasTV") + .HasColumnType("boolean"); + + b.Property("HasWC") + .HasColumnType("boolean"); + + b.Property("HasWiFi") + .HasColumnType("boolean"); + + b.Property("Number") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("CompanyId"); + + b.ToTable("Vehicles"); + }); + + modelBuilder.Entity("Server.Models.VehicleEnrollment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CancelationComment") + .HasColumnType("text"); + + b.Property("DelayTimeSpan") + .HasColumnType("interval"); + + b.Property("DepartureDateTimeUtc") + .HasColumnType("timestamp with time zone"); + + b.Property("IsCanceled") + .HasColumnType("boolean"); + + b.Property("RouteId") + .HasColumnType("integer"); + + b.Property("VehicleId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("RouteId"); + + b.HasIndex("VehicleId"); + + b.ToTable("VehicleEnrollments"); + }); + + 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("Server.Models.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Server.Models.User", 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("Server.Models.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Server.Models.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Server.Models.Address", b => + { + b.HasOne("Server.Models.City", "City") + .WithMany("Addresses") + .HasForeignKey("CityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("City"); + }); + + modelBuilder.Entity("Server.Models.City", b => + { + b.HasOne("Server.Models.State", "State") + .WithMany("Cities") + .HasForeignKey("StateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("State"); + }); + + modelBuilder.Entity("Server.Models.Company", b => + { + b.HasOne("Server.Models.User", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("Server.Models.Review", b => + { + b.HasOne("Server.Models.User", "User") + .WithMany("Reviews") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Server.Models.VehicleEnrollment", "VehicleEnrollment") + .WithMany("Reviews") + .HasForeignKey("VehicleEnrollmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + + b.Navigation("VehicleEnrollment"); + }); + + modelBuilder.Entity("Server.Models.RouteAddress", b => + { + b.HasOne("Server.Models.Address", "Address") + .WithMany("RouteAddresses") + .HasForeignKey("AddressId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Server.Models.Route", "Route") + .WithMany("RouteAddresses") + .HasForeignKey("RouteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Address"); + + b.Navigation("Route"); + }); + + modelBuilder.Entity("Server.Models.RouteAddressDetails", b => + { + b.HasOne("Server.Models.RouteAddress", "RouteAddress") + .WithMany("RouteAddressDetails") + .HasForeignKey("RouteAddressId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Server.Models.VehicleEnrollment", "VehicleEnrollment") + .WithMany("RouteAddressDetails") + .HasForeignKey("VehicleEnrollmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("RouteAddress"); + + b.Navigation("VehicleEnrollment"); + }); + + modelBuilder.Entity("Server.Models.State", b => + { + b.HasOne("Server.Models.Country", "Country") + .WithMany("States") + .HasForeignKey("CountryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Country"); + }); + + modelBuilder.Entity("Server.Models.Ticket", b => + { + b.HasOne("Server.Models.TicketGroup", "TicketGroup") + .WithMany("Tickets") + .HasForeignKey("TicketGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Server.Models.VehicleEnrollment", "VehicleEnrollment") + .WithMany("Tickets") + .HasForeignKey("VehicleEnrollmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("TicketGroup"); + + b.Navigation("VehicleEnrollment"); + }); + + modelBuilder.Entity("Server.Models.TicketGroup", b => + { + b.HasOne("Server.Models.User", "User") + .WithMany("TicketGroups") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Server.Models.User", b => + { + b.OwnsMany("Server.Models.RefreshToken", "RefreshTokens", b1 => + { + b1.Property("UserId") + .HasColumnType("text"); + + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property("Id")); + + b1.Property("CreationDateTime") + .HasColumnType("timestamp with time zone"); + + b1.Property("ExpiryDateTime") + .HasColumnType("timestamp with time zone"); + + b1.Property("Revoked") + .HasColumnType("timestamp with time zone"); + + b1.Property("Token") + .IsRequired() + .HasColumnType("text"); + + b1.HasKey("UserId", "Id"); + + b1.ToTable("RefreshToken"); + + b1.WithOwner() + .HasForeignKey("UserId"); + }); + + b.Navigation("RefreshTokens"); + }); + + modelBuilder.Entity("Server.Models.Vehicle", b => + { + b.HasOne("Server.Models.Company", "Company") + .WithMany("Vehicles") + .HasForeignKey("CompanyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Company"); + }); + + modelBuilder.Entity("Server.Models.VehicleEnrollment", b => + { + b.HasOne("Server.Models.Route", "Route") + .WithMany("VehicleEnrollments") + .HasForeignKey("RouteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Server.Models.Vehicle", "Vehicle") + .WithMany("VehicleEnrollments") + .HasForeignKey("VehicleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Route"); + + b.Navigation("Vehicle"); + }); + + modelBuilder.Entity("Server.Models.Address", b => + { + b.Navigation("RouteAddresses"); + }); + + modelBuilder.Entity("Server.Models.City", b => + { + b.Navigation("Addresses"); + }); + + modelBuilder.Entity("Server.Models.Company", b => + { + b.Navigation("Vehicles"); + }); + + modelBuilder.Entity("Server.Models.Country", b => + { + b.Navigation("States"); + }); + + modelBuilder.Entity("Server.Models.Route", b => + { + b.Navigation("RouteAddresses"); + + b.Navigation("VehicleEnrollments"); + }); + + modelBuilder.Entity("Server.Models.RouteAddress", b => + { + b.Navigation("RouteAddressDetails"); + }); + + modelBuilder.Entity("Server.Models.State", b => + { + b.Navigation("Cities"); + }); + + modelBuilder.Entity("Server.Models.TicketGroup", b => + { + b.Navigation("Tickets"); + }); + + modelBuilder.Entity("Server.Models.User", b => + { + b.Navigation("Reviews"); + + b.Navigation("TicketGroups"); + }); + + modelBuilder.Entity("Server.Models.Vehicle", b => + { + b.Navigation("VehicleEnrollments"); + }); + + modelBuilder.Entity("Server.Models.VehicleEnrollment", b => + { + b.Navigation("Reviews"); + + b.Navigation("RouteAddressDetails"); + + b.Navigation("Tickets"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Server/Migrations/20230426081251_Remove_UserName_and_NormalizedUserName_From_AspNetUsers.cs b/Server/Migrations/20230426081251_Remove_UserName_and_NormalizedUserName_From_AspNetUsers.cs new file mode 100644 index 0000000..cd548e5 --- /dev/null +++ b/Server/Migrations/20230426081251_Remove_UserName_and_NormalizedUserName_From_AspNetUsers.cs @@ -0,0 +1,105 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Server.Migrations +{ + public partial class Remove_UserName_and_NormalizedUserName_From_AspNetUsers : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "UserNameIndex", + table: "AspNetUsers"); + + migrationBuilder.DropColumn( + name: "RouteAddressDetailsId", + table: "VehicleEnrollments"); + + migrationBuilder.DropColumn( + name: "NormalizedUserName", + table: "AspNetUsers"); + + migrationBuilder.DropColumn( + name: "UserName", + table: "AspNetUsers"); + + migrationBuilder.AlterColumn( + name: "LastName", + table: "AspNetUsers", + type: "text", + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "text", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "FirstName", + table: "AspNetUsers", + type: "text", + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "text", + oldNullable: true); + + migrationBuilder.AddColumn( + name: "Patronymic", + table: "AspNetUsers", + type: "text", + nullable: false, + defaultValue: ""); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Patronymic", + table: "AspNetUsers"); + + migrationBuilder.AddColumn( + name: "RouteAddressDetailsId", + table: "VehicleEnrollments", + type: "integer", + nullable: false, + defaultValue: 0); + + migrationBuilder.AlterColumn( + name: "LastName", + table: "AspNetUsers", + type: "text", + nullable: true, + oldClrType: typeof(string), + oldType: "text"); + + migrationBuilder.AlterColumn( + name: "FirstName", + table: "AspNetUsers", + type: "text", + nullable: true, + oldClrType: typeof(string), + oldType: "text"); + + migrationBuilder.AddColumn( + name: "NormalizedUserName", + table: "AspNetUsers", + type: "character varying(256)", + maxLength: 256, + nullable: true); + + migrationBuilder.AddColumn( + name: "UserName", + table: "AspNetUsers", + type: "character varying(256)", + maxLength: 256, + nullable: true); + + migrationBuilder.CreateIndex( + name: "UserNameIndex", + table: "AspNetUsers", + column: "NormalizedUserName", + unique: true); + } + } +} diff --git a/Server/Migrations/ApplicationDbContextModelSnapshot.cs b/Server/Migrations/ApplicationDbContextModelSnapshot.cs index daf3e39..69debca 100644 --- a/Server/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/Server/Migrations/ApplicationDbContextModelSnapshot.cs @@ -458,9 +458,11 @@ namespace Server.Migrations .HasColumnType("boolean"); b.Property("FirstName") + .IsRequired() .HasColumnType("text"); b.Property("LastName") + .IsRequired() .HasColumnType("text"); b.Property("LockoutEnabled") @@ -473,13 +475,13 @@ namespace Server.Migrations .HasMaxLength(256) .HasColumnType("character varying(256)"); - b.Property("NormalizedUserName") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - b.Property("PasswordHash") .HasColumnType("text"); + b.Property("Patronymic") + .IsRequired() + .HasColumnType("text"); + b.Property("PhoneNumber") .HasColumnType("text"); @@ -492,19 +494,11 @@ namespace Server.Migrations 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); }); @@ -578,9 +572,6 @@ namespace Server.Migrations b.Property("IsCanceled") .HasColumnType("boolean"); - b.Property("RouteAddressDetailsId") - .HasColumnType("integer"); - b.Property("RouteId") .HasColumnType("integer"); diff --git a/Server/Models/User.cs b/Server/Models/User.cs index 63d439f..8d8630c 100644 --- a/Server/Models/User.cs +++ b/Server/Models/User.cs @@ -1,12 +1,21 @@ +using System.ComponentModel.DataAnnotations; using Microsoft.AspNetCore.Identity; namespace Server.Models; public class User : IdentityUser { - public string? FirstName { get; set; } - public string? LastName { get; set; } + [Required(ErrorMessage = "First Name is required")] + public string FirstName { get; set; } = null!; + + [Required(ErrorMessage = "Last Name is required")] + public string LastName { get; set; } = null!; + + [Required(ErrorMessage = "Patronymic is required")] + public string Patronymic { get; set; } = null!; + public IList RefreshTokens { get; set; } = null!; + public virtual IList TicketGroups { get; set; } = null!; public virtual IList Reviews { get; set; } = null!; } \ No newline at end of file diff --git a/Server/Program.cs b/Server/Program.cs index e2d53cb..16363c9 100644 --- a/Server/Program.cs +++ b/Server/Program.cs @@ -59,8 +59,7 @@ builder.Services.AddCors(options => { builder.Services.AddIdentityCore(options => { options.User.RequireUniqueEmail = true; - options.Password.RequiredLength = 7; - options.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567889-_."; + options.Password.RequiredLength = 8; }).AddRoles().AddEntityFrameworkStores(); // Configuration from AppSettings diff --git a/Server/Services/AuthenticationService.cs b/Server/Services/AuthenticationService.cs index e380f39..24aa425 100644 --- a/Server/Services/AuthenticationService.cs +++ b/Server/Services/AuthenticationService.cs @@ -1,3 +1,4 @@ +using System.Globalization; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Security.Cryptography; @@ -29,14 +30,30 @@ public class AuthenticationService : IAuthenticationService public async Task<(bool succeeded, string message)> RegisterAsync(RegistrationRequest regRequest) { + _userManager.UserValidators.Clear(); + var userWithSameEmail = await _userManager.FindByEmailAsync(regRequest.Email); - var userWithSameUsername = await _userManager.FindByNameAsync(regRequest.Username); - if (userWithSameEmail != null || userWithSameUsername != null) + if (userWithSameEmail != null) { - return (false, $"Email {regRequest.Email} is already registered."); + return (false, $"Email is already registered."); } - var user = new User {UserName = regRequest.Username, Email = regRequest.Email}; + var userWithSamePhone = await _userManager.Users + .SingleOrDefaultAsync(u => u.PhoneNumber == regRequest.PhoneNumber); + if (userWithSamePhone != null) + { + return (false, $"Phone is already registered."); + } + + var user = new User + { + UserName = "temp", + FirstName = regRequest.FirstName, + LastName = regRequest.LastName, + Patronymic = regRequest.Patronymic, + Email = regRequest.Email, + PhoneNumber = regRequest.PhoneNumber + }; var result = await _userManager.CreateAsync(user, regRequest.Password); if (!result.Succeeded) @@ -55,24 +72,17 @@ public class AuthenticationService : IAuthenticationService User user; - if (authRequest.EmailOrUsername.Contains("@")) - { - user = await _userManager.FindByEmailAsync(authRequest.EmailOrUsername); - } - else - { - user = await _userManager.FindByNameAsync(authRequest.EmailOrUsername); - } + user = await _userManager.FindByEmailAsync(authRequest.Email); if (user == null) { - authResponse.Message = $"No accounts registered with {authRequest.EmailOrUsername}."; + authResponse.Message = $"No accounts registered with {authRequest.Email}."; return (false, authResponse, null); } if (!await _userManager.CheckPasswordAsync(user, authRequest.Password)) { - authResponse.Message = $"Incorrect login or password."; + authResponse.Message = $"Incorrect email or password."; return (false, authResponse, null); } @@ -176,10 +186,12 @@ public class AuthenticationService : IAuthenticationService var claims = new[] { - new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), - new Claim("uid", user.Id), - new Claim(JwtRegisteredClaimNames.Sub, user.UserName), - new Claim(JwtRegisteredClaimNames.Email, user.Email) + new Claim(JwtRegisteredClaimNames.Sub, user.Id), + new Claim(JwtRegisteredClaimNames.Name, user.LastName + user.FirstName + user.Patronymic), + new Claim(JwtRegisteredClaimNames.GivenName, user.FirstName), + new Claim(JwtRegisteredClaimNames.FamilyName, user.LastName), + new Claim(JwtRegisteredClaimNames.Email, user.Email), + new Claim(JwtRegisteredClaimNames.Exp, DateTime.UtcNow.AddMinutes(_jwt.ValidityInMinutes).ToString(CultureInfo.InvariantCulture)) } .Union(userClaims) .Union(roleClaims); diff --git a/SharedModels/Requests/AuthenticationRequest.cs b/SharedModels/Requests/AuthenticationRequest.cs index e4c7c22..ba7a929 100644 --- a/SharedModels/Requests/AuthenticationRequest.cs +++ b/SharedModels/Requests/AuthenticationRequest.cs @@ -5,7 +5,9 @@ namespace SharedModels.Requests; public class AuthenticationRequest { [Required] - public string EmailOrUsername { get; set; } = null!; + [EmailAddress] + public string Email { get; set; } = null!; + [Required] public string Password { get; set; } = null!; } \ No newline at end of file diff --git a/SharedModels/Requests/RegistrationRequest.cs b/SharedModels/Requests/RegistrationRequest.cs index 4eba9a1..7f330a8 100644 --- a/SharedModels/Requests/RegistrationRequest.cs +++ b/SharedModels/Requests/RegistrationRequest.cs @@ -4,11 +4,23 @@ namespace SharedModels.Requests; public class RegistrationRequest { - [Required(ErrorMessage = "Username is required")] - public string Username { get; set; } = null!; + [Required(ErrorMessage = "Firstname is required")] + public string FirstName { get; set; } = null!; + + [Required(ErrorMessage = "Lastname is required")] + public string LastName { get; set; } = null!; + + [Required(ErrorMessage = "Patronymic is required")] + public string Patronymic { get; set; } = null!; + [Required(ErrorMessage = "Email is required")] [EmailAddress] public string Email { get; set; } = null!; + + [Required(ErrorMessage = "Phone number is required")] + [Phone] + public string PhoneNumber { get; set; } = null!; + [Required(ErrorMessage = "Password is required")] [DataType(DataType.Password)] public string Password { get; set; } = null!;