Identity Rescafolding and DBContext changes
This commit is contained in:
@@ -6,21 +6,14 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
|
|
||||||
namespace Data
|
namespace Data
|
||||||
{
|
{
|
||||||
public class RentACarDbContext : IdentityDbContext<IdentityUser>
|
public class RentACarDbContext : IdentityDbContext<User, IdentityRole, string>
|
||||||
{
|
{
|
||||||
public virtual DbSet<Car> Cars { get; set; }
|
public virtual DbSet<Car> Cars { get; set; }
|
||||||
public virtual DbSet<Rents> Rents { get; set; }
|
public virtual DbSet<Rents> Rents { get; set; }
|
||||||
private UserManager<User> userManager { get; set; }
|
|
||||||
private RoleManager<IdentityRole> roleManager { get; set; }
|
|
||||||
|
|
||||||
public RentACarDbContext()
|
|
||||||
{
|
|
||||||
//TODO: initialize UserManager and RoleManager
|
|
||||||
}
|
|
||||||
|
|
||||||
public RentACarDbContext(DbContextOptions<RentACarDbContext> dbContextOptions) : base(dbContextOptions)
|
public RentACarDbContext(DbContextOptions<RentACarDbContext> dbContextOptions) : base(dbContextOptions)
|
||||||
{
|
{
|
||||||
//TODO: initialize UserManager and RoleManager
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
@@ -33,57 +26,48 @@ namespace Data
|
|||||||
|
|
||||||
protected override async void OnModelCreating(ModelBuilder modelBuilder)
|
protected override async void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
base.OnModelCreating(modelBuilder);
|
||||||
|
|
||||||
|
this.Database.EnsureCreated();
|
||||||
string[] roles = { "Admin", "Employee" };
|
string[] roles = { "Admin", "Employee" };
|
||||||
|
|
||||||
foreach (string role in roles)
|
foreach (string role in roles)
|
||||||
{
|
{
|
||||||
if (!await roleManager.RoleExistsAsync(role))
|
IdentityRole roleToCheck = await this.Roles.FirstOrDefaultAsync(roleToCheck => roleToCheck.Name == role);
|
||||||
|
if (roleToCheck == null)
|
||||||
{
|
{
|
||||||
await roleManager.CreateAsync(new IdentityRole(role));
|
//this.Roles.Add(new IdentityRole(role));
|
||||||
|
modelBuilder.Entity<IdentityRole>().HasData(new IdentityRole(role));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
User initialUser = new User
|
PasswordHasher<User> passwordHasher = new PasswordHasher<User>();
|
||||||
|
|
||||||
|
User initialUser = new User();
|
||||||
|
initialUser.Id = Guid.NewGuid().ToString();
|
||||||
|
initialUser.UserName = "admin";
|
||||||
|
initialUser.PasswordHash = passwordHasher.HashPassword(initialUser, "admin");
|
||||||
|
|
||||||
|
|
||||||
|
if (this.Users.FirstOrDefaultAsync() != null)
|
||||||
{
|
{
|
||||||
UserName = "admin",
|
|
||||||
PasswordHash = "admin",
|
|
||||||
};
|
|
||||||
|
|
||||||
modelBuilder.Entity<User>().HasData(initialUser);
|
modelBuilder.Entity<User>().HasData(initialUser);
|
||||||
await userManager.AddToRoleAsync(initialUser, roles[0]);
|
IdentityRole<string> adminRole = await this.Roles.FirstOrDefaultAsync(role => role.Name == "Admin");
|
||||||
|
modelBuilder.Entity<IdentityUserRole<string>>().HasData(new IdentityUserRole<string> {RoleId = adminRole.Id, UserId = initialUser.Id});
|
||||||
|
}
|
||||||
|
|
||||||
//modelBuilder.Entity<User>().HasData(
|
|
||||||
// new User
|
|
||||||
// {
|
|
||||||
// Username = "user",
|
|
||||||
// Password = "user",
|
|
||||||
// FirstName = "User",
|
|
||||||
// LastName = "User",
|
|
||||||
// PersonalNumber = "0987654321",
|
|
||||||
// PhoneNumber = "0882750588",
|
|
||||||
// Email = "user@gmail.org",
|
|
||||||
// Role = User.RoleEnum.User
|
|
||||||
// }
|
|
||||||
//);
|
|
||||||
//modelBuilder.Entity<User>().HasData(
|
|
||||||
// new User
|
|
||||||
// {
|
|
||||||
// Username = "manager",
|
|
||||||
// Password = "manager",
|
|
||||||
// FirstName = "Manager",
|
|
||||||
// LastName = "Manager",
|
|
||||||
// PersonalNumber = "0987654321",
|
|
||||||
// PhoneNumber = "0882750588",
|
|
||||||
// Email = "manager@gmail.org",
|
|
||||||
// Role = User.RoleEnum.Manager
|
|
||||||
// }
|
|
||||||
//);
|
|
||||||
base.OnModelCreating(modelBuilder);
|
|
||||||
modelBuilder.Entity<User>()
|
|
||||||
.HasIndex(user => new { user.UserName })
|
|
||||||
.IsUnique(true);
|
|
||||||
modelBuilder.Entity<Rents>().HasOne(rents => rents.User);
|
modelBuilder.Entity<Rents>().HasOne(rents => rents.User);
|
||||||
modelBuilder.Entity<Rents>().HasOne(rents => rents.Car);
|
modelBuilder.Entity<Rents>().HasOne(rents => rents.Car);
|
||||||
|
|
||||||
|
modelBuilder.Entity<Car>().HasData(new Car()
|
||||||
|
{
|
||||||
|
Id = 1,
|
||||||
|
Brand = "Trabant"
|
||||||
|
}) ;
|
||||||
|
|
||||||
|
this.SaveChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,15 +10,15 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|||||||
namespace Data.Migrations
|
namespace Data.Migrations
|
||||||
{
|
{
|
||||||
[DbContext(typeof(RentACarDbContext))]
|
[DbContext(typeof(RentACarDbContext))]
|
||||||
[Migration("20220401141638_InitialMigration")]
|
[Migration("20220404172708_Changes")]
|
||||||
partial class InitialMigration
|
partial class Changes
|
||||||
{
|
{
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
#pragma warning disable 612, 618
|
#pragma warning disable 612, 618
|
||||||
modelBuilder
|
modelBuilder
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 128)
|
.HasAnnotation("Relational:MaxIdentifierLength", 128)
|
||||||
.HasAnnotation("ProductVersion", "5.0.13")
|
.HasAnnotation("ProductVersion", "5.0.15")
|
||||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||||
|
|
||||||
modelBuilder.Entity("Data.Entities.Car", b =>
|
modelBuilder.Entity("Data.Entities.Car", b =>
|
||||||
@@ -58,7 +58,7 @@ namespace Data.Migrations
|
|||||||
.HasColumnType("int")
|
.HasColumnType("int")
|
||||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||||
|
|
||||||
b.Property<int?>("CarId")
|
b.Property<int>("CarId")
|
||||||
.HasColumnType("int");
|
.HasColumnType("int");
|
||||||
|
|
||||||
b.Property<DateTime>("EndDate")
|
b.Property<DateTime>("EndDate")
|
||||||
@@ -88,10 +88,12 @@ namespace Data.Migrations
|
|||||||
.HasColumnType("int");
|
.HasColumnType("int");
|
||||||
|
|
||||||
b.Property<string>("ConcurrencyStamp")
|
b.Property<string>("ConcurrencyStamp")
|
||||||
|
.IsConcurrencyToken()
|
||||||
.HasColumnType("nvarchar(max)");
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
b.Property<string>("Email")
|
b.Property<string>("Email")
|
||||||
.HasColumnType("nvarchar(max)");
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("nvarchar(256)");
|
||||||
|
|
||||||
b.Property<bool>("EmailConfirmed")
|
b.Property<bool>("EmailConfirmed")
|
||||||
.HasColumnType("bit");
|
.HasColumnType("bit");
|
||||||
@@ -109,10 +111,12 @@ namespace Data.Migrations
|
|||||||
.HasColumnType("datetimeoffset");
|
.HasColumnType("datetimeoffset");
|
||||||
|
|
||||||
b.Property<string>("NormalizedEmail")
|
b.Property<string>("NormalizedEmail")
|
||||||
.HasColumnType("nvarchar(max)");
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("nvarchar(256)");
|
||||||
|
|
||||||
b.Property<string>("NormalizedUserName")
|
b.Property<string>("NormalizedUserName")
|
||||||
.HasColumnType("nvarchar(max)");
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("nvarchar(256)");
|
||||||
|
|
||||||
b.Property<string>("PasswordHash")
|
b.Property<string>("PasswordHash")
|
||||||
.HasColumnType("nvarchar(max)");
|
.HasColumnType("nvarchar(max)");
|
||||||
@@ -133,15 +137,20 @@ namespace Data.Migrations
|
|||||||
.HasColumnType("bit");
|
.HasColumnType("bit");
|
||||||
|
|
||||||
b.Property<string>("UserName")
|
b.Property<string>("UserName")
|
||||||
.HasColumnType("nvarchar(450)");
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("nvarchar(256)");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.HasIndex("UserName")
|
b.HasIndex("NormalizedEmail")
|
||||||
.IsUnique()
|
.HasDatabaseName("EmailIndex");
|
||||||
.HasFilter("[UserName] IS NOT NULL");
|
|
||||||
|
|
||||||
b.ToTable("User");
|
b.HasIndex("NormalizedUserName")
|
||||||
|
.IsUnique()
|
||||||
|
.HasDatabaseName("UserNameIndex")
|
||||||
|
.HasFilter("[NormalizedUserName] IS NOT NULL");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUsers");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||||
@@ -195,71 +204,6 @@ namespace Data.Migrations
|
|||||||
b.ToTable("AspNetRoleClaims");
|
b.ToTable("AspNetRoleClaims");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Id")
|
|
||||||
.HasColumnType("nvarchar(450)");
|
|
||||||
|
|
||||||
b.Property<int>("AccessFailedCount")
|
|
||||||
.HasColumnType("int");
|
|
||||||
|
|
||||||
b.Property<string>("ConcurrencyStamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.HasColumnType("nvarchar(max)");
|
|
||||||
|
|
||||||
b.Property<string>("Email")
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("nvarchar(256)");
|
|
||||||
|
|
||||||
b.Property<bool>("EmailConfirmed")
|
|
||||||
.HasColumnType("bit");
|
|
||||||
|
|
||||||
b.Property<bool>("LockoutEnabled")
|
|
||||||
.HasColumnType("bit");
|
|
||||||
|
|
||||||
b.Property<DateTimeOffset?>("LockoutEnd")
|
|
||||||
.HasColumnType("datetimeoffset");
|
|
||||||
|
|
||||||
b.Property<string>("NormalizedEmail")
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("nvarchar(256)");
|
|
||||||
|
|
||||||
b.Property<string>("NormalizedUserName")
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("nvarchar(256)");
|
|
||||||
|
|
||||||
b.Property<string>("PasswordHash")
|
|
||||||
.HasColumnType("nvarchar(max)");
|
|
||||||
|
|
||||||
b.Property<string>("PhoneNumber")
|
|
||||||
.HasColumnType("nvarchar(max)");
|
|
||||||
|
|
||||||
b.Property<bool>("PhoneNumberConfirmed")
|
|
||||||
.HasColumnType("bit");
|
|
||||||
|
|
||||||
b.Property<string>("SecurityStamp")
|
|
||||||
.HasColumnType("nvarchar(max)");
|
|
||||||
|
|
||||||
b.Property<bool>("TwoFactorEnabled")
|
|
||||||
.HasColumnType("bit");
|
|
||||||
|
|
||||||
b.Property<string>("UserName")
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("nvarchar(256)");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("NormalizedEmail")
|
|
||||||
.HasDatabaseName("EmailIndex");
|
|
||||||
|
|
||||||
b.HasIndex("NormalizedUserName")
|
|
||||||
.IsUnique()
|
|
||||||
.HasDatabaseName("UserNameIndex")
|
|
||||||
.HasFilter("[NormalizedUserName] IS NOT NULL");
|
|
||||||
|
|
||||||
b.ToTable("AspNetUsers");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
@@ -344,7 +288,9 @@ namespace Data.Migrations
|
|||||||
{
|
{
|
||||||
b.HasOne("Data.Entities.Car", "Car")
|
b.HasOne("Data.Entities.Car", "Car")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("CarId");
|
.HasForeignKey("CarId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
b.HasOne("Data.Entities.User", "User")
|
b.HasOne("Data.Entities.User", "User")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
@@ -366,7 +312,7 @@ namespace Data.Migrations
|
|||||||
|
|
||||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
|
b.HasOne("Data.Entities.User", null)
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("UserId")
|
.HasForeignKey("UserId")
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
@@ -375,7 +321,7 @@ namespace Data.Migrations
|
|||||||
|
|
||||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
|
b.HasOne("Data.Entities.User", null)
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("UserId")
|
.HasForeignKey("UserId")
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
@@ -390,7 +336,7 @@ namespace Data.Migrations
|
|||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
|
|
||||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
|
b.HasOne("Data.Entities.User", null)
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("UserId")
|
.HasForeignKey("UserId")
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
@@ -399,7 +345,7 @@ namespace Data.Migrations
|
|||||||
|
|
||||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
|
b.HasOne("Data.Entities.User", null)
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("UserId")
|
.HasForeignKey("UserId")
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
@@ -3,7 +3,7 @@ using Microsoft.EntityFrameworkCore.Migrations;
|
|||||||
|
|
||||||
namespace Data.Migrations
|
namespace Data.Migrations
|
||||||
{
|
{
|
||||||
public partial class InitialMigration : Migration
|
public partial class Changes : Migration
|
||||||
{
|
{
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
{
|
{
|
||||||
@@ -26,6 +26,9 @@ namespace Data.Migrations
|
|||||||
columns: table => new
|
columns: table => new
|
||||||
{
|
{
|
||||||
Id = table.Column<string>(type: "nvarchar(450)", nullable: false),
|
Id = table.Column<string>(type: "nvarchar(450)", nullable: false),
|
||||||
|
FirstName = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||||
|
LastName = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||||
|
PersonalNumber = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||||
UserName = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
|
UserName = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
|
||||||
NormalizedUserName = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
|
NormalizedUserName = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
|
||||||
Email = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
|
Email = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
|
||||||
@@ -64,34 +67,6 @@ namespace Data.Migrations
|
|||||||
table.PrimaryKey("PK_Cars", x => x.Id);
|
table.PrimaryKey("PK_Cars", x => x.Id);
|
||||||
});
|
});
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "User",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
Id = table.Column<string>(type: "nvarchar(450)", nullable: false),
|
|
||||||
FirstName = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
|
||||||
LastName = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
|
||||||
PersonalNumber = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
|
||||||
UserName = table.Column<string>(type: "nvarchar(450)", nullable: true),
|
|
||||||
NormalizedUserName = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
|
||||||
Email = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
|
||||||
NormalizedEmail = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
|
||||||
EmailConfirmed = table.Column<bool>(type: "bit", nullable: false),
|
|
||||||
PasswordHash = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
|
||||||
SecurityStamp = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
|
||||||
ConcurrencyStamp = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
|
||||||
PhoneNumber = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
|
||||||
PhoneNumberConfirmed = table.Column<bool>(type: "bit", nullable: false),
|
|
||||||
TwoFactorEnabled = table.Column<bool>(type: "bit", nullable: false),
|
|
||||||
LockoutEnd = table.Column<DateTimeOffset>(type: "datetimeoffset", nullable: true),
|
|
||||||
LockoutEnabled = table.Column<bool>(type: "bit", nullable: false),
|
|
||||||
AccessFailedCount = table.Column<int>(type: "int", nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_User", x => x.Id);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
migrationBuilder.CreateTable(
|
||||||
name: "AspNetRoleClaims",
|
name: "AspNetRoleClaims",
|
||||||
columns: table => new
|
columns: table => new
|
||||||
@@ -204,7 +179,7 @@ namespace Data.Migrations
|
|||||||
{
|
{
|
||||||
Id = table.Column<int>(type: "int", nullable: false)
|
Id = table.Column<int>(type: "int", nullable: false)
|
||||||
.Annotation("SqlServer:Identity", "1, 1"),
|
.Annotation("SqlServer:Identity", "1, 1"),
|
||||||
CarId = table.Column<int>(type: "int", nullable: true),
|
CarId = table.Column<int>(type: "int", nullable: false),
|
||||||
StartDate = table.Column<DateTime>(type: "datetime2", nullable: false),
|
StartDate = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||||
EndDate = table.Column<DateTime>(type: "datetime2", nullable: false),
|
EndDate = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||||
UserId = table.Column<string>(type: "nvarchar(450)", nullable: true)
|
UserId = table.Column<string>(type: "nvarchar(450)", nullable: true)
|
||||||
@@ -212,18 +187,18 @@ namespace Data.Migrations
|
|||||||
constraints: table =>
|
constraints: table =>
|
||||||
{
|
{
|
||||||
table.PrimaryKey("PK_Rents", x => x.Id);
|
table.PrimaryKey("PK_Rents", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Rents_AspNetUsers_UserId",
|
||||||
|
column: x => x.UserId,
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
table.ForeignKey(
|
table.ForeignKey(
|
||||||
name: "FK_Rents_Cars_CarId",
|
name: "FK_Rents_Cars_CarId",
|
||||||
column: x => x.CarId,
|
column: x => x.CarId,
|
||||||
principalTable: "Cars",
|
principalTable: "Cars",
|
||||||
principalColumn: "Id",
|
principalColumn: "Id",
|
||||||
onDelete: ReferentialAction.Restrict);
|
onDelete: ReferentialAction.Cascade);
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_Rents_User_UserId",
|
|
||||||
column: x => x.UserId,
|
|
||||||
principalTable: "User",
|
|
||||||
principalColumn: "Id",
|
|
||||||
onDelete: ReferentialAction.Restrict);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
migrationBuilder.CreateIndex(
|
||||||
@@ -274,13 +249,6 @@ namespace Data.Migrations
|
|||||||
name: "IX_Rents_UserId",
|
name: "IX_Rents_UserId",
|
||||||
table: "Rents",
|
table: "Rents",
|
||||||
column: "UserId");
|
column: "UserId");
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_User_UserName",
|
|
||||||
table: "User",
|
|
||||||
column: "UserName",
|
|
||||||
unique: true,
|
|
||||||
filter: "[UserName] IS NOT NULL");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
@@ -311,9 +279,6 @@ namespace Data.Migrations
|
|||||||
|
|
||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "Cars");
|
name: "Cars");
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "User");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16,7 +16,7 @@ namespace Data.Migrations
|
|||||||
#pragma warning disable 612, 618
|
#pragma warning disable 612, 618
|
||||||
modelBuilder
|
modelBuilder
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 128)
|
.HasAnnotation("Relational:MaxIdentifierLength", 128)
|
||||||
.HasAnnotation("ProductVersion", "5.0.13")
|
.HasAnnotation("ProductVersion", "5.0.15")
|
||||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||||
|
|
||||||
modelBuilder.Entity("Data.Entities.Car", b =>
|
modelBuilder.Entity("Data.Entities.Car", b =>
|
||||||
@@ -56,7 +56,7 @@ namespace Data.Migrations
|
|||||||
.HasColumnType("int")
|
.HasColumnType("int")
|
||||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||||
|
|
||||||
b.Property<int?>("CarId")
|
b.Property<int>("CarId")
|
||||||
.HasColumnType("int");
|
.HasColumnType("int");
|
||||||
|
|
||||||
b.Property<DateTime>("EndDate")
|
b.Property<DateTime>("EndDate")
|
||||||
@@ -86,10 +86,12 @@ namespace Data.Migrations
|
|||||||
.HasColumnType("int");
|
.HasColumnType("int");
|
||||||
|
|
||||||
b.Property<string>("ConcurrencyStamp")
|
b.Property<string>("ConcurrencyStamp")
|
||||||
|
.IsConcurrencyToken()
|
||||||
.HasColumnType("nvarchar(max)");
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
b.Property<string>("Email")
|
b.Property<string>("Email")
|
||||||
.HasColumnType("nvarchar(max)");
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("nvarchar(256)");
|
||||||
|
|
||||||
b.Property<bool>("EmailConfirmed")
|
b.Property<bool>("EmailConfirmed")
|
||||||
.HasColumnType("bit");
|
.HasColumnType("bit");
|
||||||
@@ -107,10 +109,12 @@ namespace Data.Migrations
|
|||||||
.HasColumnType("datetimeoffset");
|
.HasColumnType("datetimeoffset");
|
||||||
|
|
||||||
b.Property<string>("NormalizedEmail")
|
b.Property<string>("NormalizedEmail")
|
||||||
.HasColumnType("nvarchar(max)");
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("nvarchar(256)");
|
||||||
|
|
||||||
b.Property<string>("NormalizedUserName")
|
b.Property<string>("NormalizedUserName")
|
||||||
.HasColumnType("nvarchar(max)");
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("nvarchar(256)");
|
||||||
|
|
||||||
b.Property<string>("PasswordHash")
|
b.Property<string>("PasswordHash")
|
||||||
.HasColumnType("nvarchar(max)");
|
.HasColumnType("nvarchar(max)");
|
||||||
@@ -131,15 +135,20 @@ namespace Data.Migrations
|
|||||||
.HasColumnType("bit");
|
.HasColumnType("bit");
|
||||||
|
|
||||||
b.Property<string>("UserName")
|
b.Property<string>("UserName")
|
||||||
.HasColumnType("nvarchar(450)");
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("nvarchar(256)");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.HasIndex("UserName")
|
b.HasIndex("NormalizedEmail")
|
||||||
.IsUnique()
|
.HasDatabaseName("EmailIndex");
|
||||||
.HasFilter("[UserName] IS NOT NULL");
|
|
||||||
|
|
||||||
b.ToTable("User");
|
b.HasIndex("NormalizedUserName")
|
||||||
|
.IsUnique()
|
||||||
|
.HasDatabaseName("UserNameIndex")
|
||||||
|
.HasFilter("[NormalizedUserName] IS NOT NULL");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUsers");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||||
@@ -193,71 +202,6 @@ namespace Data.Migrations
|
|||||||
b.ToTable("AspNetRoleClaims");
|
b.ToTable("AspNetRoleClaims");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Id")
|
|
||||||
.HasColumnType("nvarchar(450)");
|
|
||||||
|
|
||||||
b.Property<int>("AccessFailedCount")
|
|
||||||
.HasColumnType("int");
|
|
||||||
|
|
||||||
b.Property<string>("ConcurrencyStamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.HasColumnType("nvarchar(max)");
|
|
||||||
|
|
||||||
b.Property<string>("Email")
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("nvarchar(256)");
|
|
||||||
|
|
||||||
b.Property<bool>("EmailConfirmed")
|
|
||||||
.HasColumnType("bit");
|
|
||||||
|
|
||||||
b.Property<bool>("LockoutEnabled")
|
|
||||||
.HasColumnType("bit");
|
|
||||||
|
|
||||||
b.Property<DateTimeOffset?>("LockoutEnd")
|
|
||||||
.HasColumnType("datetimeoffset");
|
|
||||||
|
|
||||||
b.Property<string>("NormalizedEmail")
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("nvarchar(256)");
|
|
||||||
|
|
||||||
b.Property<string>("NormalizedUserName")
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("nvarchar(256)");
|
|
||||||
|
|
||||||
b.Property<string>("PasswordHash")
|
|
||||||
.HasColumnType("nvarchar(max)");
|
|
||||||
|
|
||||||
b.Property<string>("PhoneNumber")
|
|
||||||
.HasColumnType("nvarchar(max)");
|
|
||||||
|
|
||||||
b.Property<bool>("PhoneNumberConfirmed")
|
|
||||||
.HasColumnType("bit");
|
|
||||||
|
|
||||||
b.Property<string>("SecurityStamp")
|
|
||||||
.HasColumnType("nvarchar(max)");
|
|
||||||
|
|
||||||
b.Property<bool>("TwoFactorEnabled")
|
|
||||||
.HasColumnType("bit");
|
|
||||||
|
|
||||||
b.Property<string>("UserName")
|
|
||||||
.HasMaxLength(256)
|
|
||||||
.HasColumnType("nvarchar(256)");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("NormalizedEmail")
|
|
||||||
.HasDatabaseName("EmailIndex");
|
|
||||||
|
|
||||||
b.HasIndex("NormalizedUserName")
|
|
||||||
.IsUnique()
|
|
||||||
.HasDatabaseName("UserNameIndex")
|
|
||||||
.HasFilter("[NormalizedUserName] IS NOT NULL");
|
|
||||||
|
|
||||||
b.ToTable("AspNetUsers");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
@@ -342,7 +286,9 @@ namespace Data.Migrations
|
|||||||
{
|
{
|
||||||
b.HasOne("Data.Entities.Car", "Car")
|
b.HasOne("Data.Entities.Car", "Car")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("CarId");
|
.HasForeignKey("CarId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
b.HasOne("Data.Entities.User", "User")
|
b.HasOne("Data.Entities.User", "User")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
@@ -364,7 +310,7 @@ namespace Data.Migrations
|
|||||||
|
|
||||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
|
b.HasOne("Data.Entities.User", null)
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("UserId")
|
.HasForeignKey("UserId")
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
@@ -373,7 +319,7 @@ namespace Data.Migrations
|
|||||||
|
|
||||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
|
b.HasOne("Data.Entities.User", null)
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("UserId")
|
.HasForeignKey("UserId")
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
@@ -388,7 +334,7 @@ namespace Data.Migrations
|
|||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
|
|
||||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
|
b.HasOne("Data.Entities.User", null)
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("UserId")
|
.HasForeignKey("UserId")
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
@@ -397,7 +343,7 @@ namespace Data.Migrations
|
|||||||
|
|
||||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
|
b.HasOne("Data.Entities.User", null)
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("UserId")
|
.HasForeignKey("UserId")
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
using System;
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -9,13 +11,13 @@ namespace Data.Entities
|
|||||||
public class Rents
|
public class Rents
|
||||||
{
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
|
[ForeignKey("Car")]
|
||||||
|
public int CarId { get; set; }
|
||||||
public virtual Car Car { get; set; }
|
public virtual Car Car { get; set; }
|
||||||
|
|
||||||
public DateTime StartDate { get; set; }
|
public DateTime StartDate { get; set; }
|
||||||
|
|
||||||
public DateTime EndDate { get; set; }
|
public DateTime EndDate { get; set; }
|
||||||
|
[ForeignKey("User")]
|
||||||
|
public string UserId { get; set; }
|
||||||
public virtual User User { get; set; }
|
public virtual User User { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using Data;
|
using Data;
|
||||||
|
using Data.Entities;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Identity.UI;
|
using Microsoft.AspNetCore.Identity.UI;
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
@page
|
||||||
|
@model AccessDeniedModel
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Access denied";
|
||||||
|
}
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<h1 class="text-danger">@ViewData["Title"]</h1>
|
||||||
|
<p class="text-danger">You do not have access to this resource.</p>
|
||||||
|
</header>
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
|
|
||||||
|
namespace WebApp.Areas.Identity.Pages.Account
|
||||||
|
{
|
||||||
|
public class AccessDeniedModel : PageModel
|
||||||
|
{
|
||||||
|
public void OnGet()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -14,9 +14,9 @@
|
|||||||
<hr />
|
<hr />
|
||||||
<div asp-validation-summary="All" class="text-danger"></div>
|
<div asp-validation-summary="All" class="text-danger"></div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label asp-for="Input.Username"></label>
|
<label asp-for="Input.Email"></label>
|
||||||
<input asp-for="Input.Username" class="form-control" />
|
<input asp-for="Input.Email" class="form-control" />
|
||||||
<span asp-validation-for="Input.Username" class="text-danger"></span>
|
<span asp-validation-for="Input.Email" class="text-danger"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label asp-for="Input.Password"></label>
|
<label asp-for="Input.Password"></label>
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ using System.Linq;
|
|||||||
using System.Text.Encodings.Web;
|
using System.Text.Encodings.Web;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Data.Entities;
|
||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.AspNetCore.Authentication;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Data.Entities;
|
|
||||||
|
|
||||||
namespace WebApp.Areas.Identity.Pages.Account
|
namespace WebApp.Areas.Identity.Pages.Account
|
||||||
{
|
{
|
||||||
@@ -44,7 +44,8 @@ namespace WebApp.Areas.Identity.Pages.Account
|
|||||||
public class InputModel
|
public class InputModel
|
||||||
{
|
{
|
||||||
[Required]
|
[Required]
|
||||||
public string Username { get; set; }
|
[EmailAddress]
|
||||||
|
public string Email { get; set; }
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
[DataType(DataType.Password)]
|
[DataType(DataType.Password)]
|
||||||
@@ -81,7 +82,7 @@ namespace WebApp.Areas.Identity.Pages.Account
|
|||||||
{
|
{
|
||||||
// This doesn't count login failures towards account lockout
|
// This doesn't count login failures towards account lockout
|
||||||
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
|
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
|
||||||
var result = await _signInManager.PasswordSignInAsync(Input.Username, Input.Password, Input.RememberMe, lockoutOnFailure: false);
|
var result = await _signInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: false);
|
||||||
if (result.Succeeded)
|
if (result.Succeeded)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("User logged in.");
|
_logger.LogInformation("User logged in.");
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Data.Entities;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Data.Entities;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
@page
|
||||||
|
@model ChangePasswordModel
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Change password";
|
||||||
|
ViewData["ActivePage"] = ManageNavPages.ChangePassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
<h4>@ViewData["Title"]</h4>
|
||||||
|
<partial name="_StatusMessage" for="StatusMessage" />
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<form id="change-password-form" method="post">
|
||||||
|
<div asp-validation-summary="All" class="text-danger"></div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Input.OldPassword"></label>
|
||||||
|
<input asp-for="Input.OldPassword" class="form-control" />
|
||||||
|
<span asp-validation-for="Input.OldPassword" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Input.NewPassword"></label>
|
||||||
|
<input asp-for="Input.NewPassword" class="form-control" />
|
||||||
|
<span asp-validation-for="Input.NewPassword" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Input.ConfirmPassword"></label>
|
||||||
|
<input asp-for="Input.ConfirmPassword" class="form-control" />
|
||||||
|
<span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary">Update password</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
|
<partial name="_ValidationScriptsPartial" />
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Data.Entities;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
namespace WebApp.Areas.Identity.Pages.Account.Manage
|
||||||
|
{
|
||||||
|
public class ChangePasswordModel : PageModel
|
||||||
|
{
|
||||||
|
private readonly UserManager<User> _userManager;
|
||||||
|
private readonly SignInManager<User> _signInManager;
|
||||||
|
private readonly ILogger<ChangePasswordModel> _logger;
|
||||||
|
|
||||||
|
public ChangePasswordModel(
|
||||||
|
UserManager<User> userManager,
|
||||||
|
SignInManager<User> signInManager,
|
||||||
|
ILogger<ChangePasswordModel> logger)
|
||||||
|
{
|
||||||
|
_userManager = userManager;
|
||||||
|
_signInManager = signInManager;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BindProperty]
|
||||||
|
public InputModel Input { get; set; }
|
||||||
|
|
||||||
|
[TempData]
|
||||||
|
public string StatusMessage { get; set; }
|
||||||
|
|
||||||
|
public class InputModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
[DataType(DataType.Password)]
|
||||||
|
[Display(Name = "Current password")]
|
||||||
|
public string OldPassword { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
|
||||||
|
[DataType(DataType.Password)]
|
||||||
|
[Display(Name = "New password")]
|
||||||
|
public string NewPassword { get; set; }
|
||||||
|
|
||||||
|
[DataType(DataType.Password)]
|
||||||
|
[Display(Name = "Confirm new password")]
|
||||||
|
[Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
|
||||||
|
public string ConfirmPassword { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IActionResult> OnGetAsync()
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var hasPassword = await _userManager.HasPasswordAsync(user);
|
||||||
|
if (!hasPassword)
|
||||||
|
{
|
||||||
|
return RedirectToPage("./SetPassword");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Page();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IActionResult> OnPostAsync()
|
||||||
|
{
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
return Page();
|
||||||
|
}
|
||||||
|
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var changePasswordResult = await _userManager.ChangePasswordAsync(user, Input.OldPassword, Input.NewPassword);
|
||||||
|
if (!changePasswordResult.Succeeded)
|
||||||
|
{
|
||||||
|
foreach (var error in changePasswordResult.Errors)
|
||||||
|
{
|
||||||
|
ModelState.AddModelError(string.Empty, error.Description);
|
||||||
|
}
|
||||||
|
return Page();
|
||||||
|
}
|
||||||
|
|
||||||
|
await _signInManager.RefreshSignInAsync(user);
|
||||||
|
_logger.LogInformation("User changed their password successfully.");
|
||||||
|
StatusMessage = "Your password has been changed.";
|
||||||
|
|
||||||
|
return RedirectToPage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
@page
|
||||||
|
@model DeletePersonalDataModel
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Delete Personal Data";
|
||||||
|
ViewData["ActivePage"] = ManageNavPages.PersonalData;
|
||||||
|
}
|
||||||
|
|
||||||
|
<h4>@ViewData["Title"]</h4>
|
||||||
|
|
||||||
|
<div class="alert alert-warning" role="alert">
|
||||||
|
<p>
|
||||||
|
<strong>Deleting this data will permanently remove your account, and this cannot be recovered.</strong>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<form id="delete-user" method="post" class="form-group">
|
||||||
|
<div asp-validation-summary="All" class="text-danger"></div>
|
||||||
|
@if (Model.RequirePassword)
|
||||||
|
{
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Input.Password"></label>
|
||||||
|
<input asp-for="Input.Password" class="form-control" />
|
||||||
|
<span asp-validation-for="Input.Password" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<button class="btn btn-danger" type="submit">Delete data and close my account</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
|
<partial name="_ValidationScriptsPartial" />
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Data.Entities;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace WebApp.Areas.Identity.Pages.Account.Manage
|
||||||
|
{
|
||||||
|
public class DeletePersonalDataModel : PageModel
|
||||||
|
{
|
||||||
|
private readonly UserManager<User> _userManager;
|
||||||
|
private readonly SignInManager<User> _signInManager;
|
||||||
|
private readonly ILogger<DeletePersonalDataModel> _logger;
|
||||||
|
|
||||||
|
public DeletePersonalDataModel(
|
||||||
|
UserManager<User> userManager,
|
||||||
|
SignInManager<User> signInManager,
|
||||||
|
ILogger<DeletePersonalDataModel> logger)
|
||||||
|
{
|
||||||
|
_userManager = userManager;
|
||||||
|
_signInManager = signInManager;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BindProperty]
|
||||||
|
public InputModel Input { get; set; }
|
||||||
|
|
||||||
|
public class InputModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
[DataType(DataType.Password)]
|
||||||
|
public string Password { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool RequirePassword { get; set; }
|
||||||
|
|
||||||
|
public async Task<IActionResult> OnGet()
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
RequirePassword = await _userManager.HasPasswordAsync(user);
|
||||||
|
return Page();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IActionResult> OnPostAsync()
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
RequirePassword = await _userManager.HasPasswordAsync(user);
|
||||||
|
if (RequirePassword)
|
||||||
|
{
|
||||||
|
if (!await _userManager.CheckPasswordAsync(user, Input.Password))
|
||||||
|
{
|
||||||
|
ModelState.AddModelError(string.Empty, "Incorrect password.");
|
||||||
|
return Page();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = await _userManager.DeleteAsync(user);
|
||||||
|
var userId = await _userManager.GetUserIdAsync(user);
|
||||||
|
if (!result.Succeeded)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Unexpected error occurred deleting user with ID '{userId}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
await _signInManager.SignOutAsync();
|
||||||
|
|
||||||
|
_logger.LogInformation("User with ID '{UserId}' deleted themselves.", userId);
|
||||||
|
|
||||||
|
return Redirect("~/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
@page
|
||||||
|
@model DownloadPersonalDataModel
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Download Your Data";
|
||||||
|
ViewData["ActivePage"] = ManageNavPages.PersonalData;
|
||||||
|
}
|
||||||
|
|
||||||
|
<h4>@ViewData["Title"]</h4>
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
|
<partial name="_ValidationScriptsPartial" />
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Data.Entities;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace WebApp.Areas.Identity.Pages.Account.Manage
|
||||||
|
{
|
||||||
|
public class DownloadPersonalDataModel : PageModel
|
||||||
|
{
|
||||||
|
private readonly UserManager<User> _userManager;
|
||||||
|
private readonly ILogger<DownloadPersonalDataModel> _logger;
|
||||||
|
|
||||||
|
public DownloadPersonalDataModel(
|
||||||
|
UserManager<User> userManager,
|
||||||
|
ILogger<DownloadPersonalDataModel> logger)
|
||||||
|
{
|
||||||
|
_userManager = userManager;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IActionResult> OnPostAsync()
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInformation("User with ID '{UserId}' asked for their personal data.", _userManager.GetUserId(User));
|
||||||
|
|
||||||
|
// Only include personal data for download
|
||||||
|
var personalData = new Dictionary<string, string>();
|
||||||
|
var personalDataProps = typeof(User).GetProperties().Where(
|
||||||
|
prop => Attribute.IsDefined(prop, typeof(PersonalDataAttribute)));
|
||||||
|
foreach (var p in personalDataProps)
|
||||||
|
{
|
||||||
|
personalData.Add(p.Name, p.GetValue(user)?.ToString() ?? "null");
|
||||||
|
}
|
||||||
|
|
||||||
|
var logins = await _userManager.GetLoginsAsync(user);
|
||||||
|
foreach (var l in logins)
|
||||||
|
{
|
||||||
|
personalData.Add($"{l.LoginProvider} external login provider key", l.ProviderKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
Response.Headers.Add("Content-Disposition", "attachment; filename=PersonalData.json");
|
||||||
|
return new FileContentResult(JsonSerializer.SerializeToUtf8Bytes(personalData), "application/json");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
@page
|
||||||
|
@model EmailModel
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Manage Email";
|
||||||
|
ViewData["ActivePage"] = ManageNavPages.Email;
|
||||||
|
}
|
||||||
|
|
||||||
|
<h4>@ViewData["Title"]</h4>
|
||||||
|
<partial name="_StatusMessage" model="Model.StatusMessage" />
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<form id="email-form" method="post">
|
||||||
|
<div asp-validation-summary="All" class="text-danger"></div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Email"></label>
|
||||||
|
@if (Model.IsEmailConfirmed)
|
||||||
|
{
|
||||||
|
<div class="input-group">
|
||||||
|
<input asp-for="Email" class="form-control" disabled />
|
||||||
|
<div class="input-group-append">
|
||||||
|
<span class="input-group-text text-success font-weight-bold">✓</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<input asp-for="Email" class="form-control" disabled />
|
||||||
|
<button id="email-verification" type="submit" asp-page-handler="SendVerificationEmail" class="btn btn-link">Send verification email</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Input.NewEmail"></label>
|
||||||
|
<input asp-for="Input.NewEmail" class="form-control" />
|
||||||
|
<span asp-validation-for="Input.NewEmail" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
<button id="change-email-button" type="submit" asp-page-handler="ChangeEmail" class="btn btn-primary">Change email</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
|
<partial name="_ValidationScriptsPartial" />
|
||||||
|
}
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Encodings.Web;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Data.Entities;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
|
using Microsoft.AspNetCore.WebUtilities;
|
||||||
|
|
||||||
|
namespace WebApp.Areas.Identity.Pages.Account.Manage
|
||||||
|
{
|
||||||
|
public partial class EmailModel : PageModel
|
||||||
|
{
|
||||||
|
private readonly UserManager<User> _userManager;
|
||||||
|
private readonly SignInManager<User> _signInManager;
|
||||||
|
private readonly IEmailSender _emailSender;
|
||||||
|
|
||||||
|
public EmailModel(
|
||||||
|
UserManager<User> userManager,
|
||||||
|
SignInManager<User> signInManager,
|
||||||
|
IEmailSender emailSender)
|
||||||
|
{
|
||||||
|
_userManager = userManager;
|
||||||
|
_signInManager = signInManager;
|
||||||
|
_emailSender = emailSender;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Username { get; set; }
|
||||||
|
|
||||||
|
public string Email { get; set; }
|
||||||
|
|
||||||
|
public bool IsEmailConfirmed { get; set; }
|
||||||
|
|
||||||
|
[TempData]
|
||||||
|
public string StatusMessage { get; set; }
|
||||||
|
|
||||||
|
[BindProperty]
|
||||||
|
public InputModel Input { get; set; }
|
||||||
|
|
||||||
|
public class InputModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
[EmailAddress]
|
||||||
|
[Display(Name = "New email")]
|
||||||
|
public string NewEmail { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadAsync(User user)
|
||||||
|
{
|
||||||
|
var email = await _userManager.GetEmailAsync(user);
|
||||||
|
Email = email;
|
||||||
|
|
||||||
|
Input = new InputModel
|
||||||
|
{
|
||||||
|
NewEmail = email,
|
||||||
|
};
|
||||||
|
|
||||||
|
IsEmailConfirmed = await _userManager.IsEmailConfirmedAsync(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IActionResult> OnGetAsync()
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
await LoadAsync(user);
|
||||||
|
return Page();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IActionResult> OnPostChangeEmailAsync()
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
await LoadAsync(user);
|
||||||
|
return Page();
|
||||||
|
}
|
||||||
|
|
||||||
|
var email = await _userManager.GetEmailAsync(user);
|
||||||
|
if (Input.NewEmail != email)
|
||||||
|
{
|
||||||
|
var userId = await _userManager.GetUserIdAsync(user);
|
||||||
|
var code = await _userManager.GenerateChangeEmailTokenAsync(user, Input.NewEmail);
|
||||||
|
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
|
||||||
|
var callbackUrl = Url.Page(
|
||||||
|
"/Account/ConfirmEmailChange",
|
||||||
|
pageHandler: null,
|
||||||
|
values: new { userId = userId, email = Input.NewEmail, code = code },
|
||||||
|
protocol: Request.Scheme);
|
||||||
|
await _emailSender.SendEmailAsync(
|
||||||
|
Input.NewEmail,
|
||||||
|
"Confirm your email",
|
||||||
|
$"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
|
||||||
|
|
||||||
|
StatusMessage = "Confirmation link to change email sent. Please check your email.";
|
||||||
|
return RedirectToPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusMessage = "Your email is unchanged.";
|
||||||
|
return RedirectToPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IActionResult> OnPostSendVerificationEmailAsync()
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
await LoadAsync(user);
|
||||||
|
return Page();
|
||||||
|
}
|
||||||
|
|
||||||
|
var userId = await _userManager.GetUserIdAsync(user);
|
||||||
|
var email = await _userManager.GetEmailAsync(user);
|
||||||
|
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
||||||
|
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
|
||||||
|
var callbackUrl = Url.Page(
|
||||||
|
"/Account/ConfirmEmail",
|
||||||
|
pageHandler: null,
|
||||||
|
values: new { area = "Identity", userId = userId, code = code },
|
||||||
|
protocol: Request.Scheme);
|
||||||
|
await _emailSender.SendEmailAsync(
|
||||||
|
email,
|
||||||
|
"Confirm your email",
|
||||||
|
$"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
|
||||||
|
|
||||||
|
StatusMessage = "Verification email sent. Please check your email.";
|
||||||
|
return RedirectToPage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
@page
|
||||||
|
@model IndexModel
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Profile";
|
||||||
|
ViewData["ActivePage"] = ManageNavPages.Index;
|
||||||
|
}
|
||||||
|
|
||||||
|
<h4>@ViewData["Title"]</h4>
|
||||||
|
<partial name="_StatusMessage" model="Model.StatusMessage" />
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<form id="profile-form" method="post">
|
||||||
|
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Username"></label>
|
||||||
|
<input asp-for="Username" class="form-control" disabled />
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Input.PhoneNumber"></label>
|
||||||
|
<input asp-for="Input.PhoneNumber" class="form-control" />
|
||||||
|
<span asp-validation-for="Input.PhoneNumber" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
<button id="update-profile-button" type="submit" class="btn btn-primary">Save</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
|
<partial name="_ValidationScriptsPartial" />
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Data.Entities;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
|
|
||||||
|
namespace WebApp.Areas.Identity.Pages.Account.Manage
|
||||||
|
{
|
||||||
|
public partial class IndexModel : PageModel
|
||||||
|
{
|
||||||
|
private readonly UserManager<User> _userManager;
|
||||||
|
private readonly SignInManager<User> _signInManager;
|
||||||
|
|
||||||
|
public IndexModel(
|
||||||
|
UserManager<User> userManager,
|
||||||
|
SignInManager<User> signInManager)
|
||||||
|
{
|
||||||
|
_userManager = userManager;
|
||||||
|
_signInManager = signInManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Username { get; set; }
|
||||||
|
|
||||||
|
[TempData]
|
||||||
|
public string StatusMessage { get; set; }
|
||||||
|
|
||||||
|
[BindProperty]
|
||||||
|
public InputModel Input { get; set; }
|
||||||
|
|
||||||
|
public class InputModel
|
||||||
|
{
|
||||||
|
[Phone]
|
||||||
|
[Display(Name = "Phone number")]
|
||||||
|
public string PhoneNumber { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadAsync(User user)
|
||||||
|
{
|
||||||
|
var userName = await _userManager.GetUserNameAsync(user);
|
||||||
|
var phoneNumber = await _userManager.GetPhoneNumberAsync(user);
|
||||||
|
|
||||||
|
Username = userName;
|
||||||
|
|
||||||
|
Input = new InputModel
|
||||||
|
{
|
||||||
|
PhoneNumber = phoneNumber
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IActionResult> OnGetAsync()
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
await LoadAsync(user);
|
||||||
|
return Page();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IActionResult> OnPostAsync()
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
await LoadAsync(user);
|
||||||
|
return Page();
|
||||||
|
}
|
||||||
|
|
||||||
|
var phoneNumber = await _userManager.GetPhoneNumberAsync(user);
|
||||||
|
if (Input.PhoneNumber != phoneNumber)
|
||||||
|
{
|
||||||
|
var setPhoneResult = await _userManager.SetPhoneNumberAsync(user, Input.PhoneNumber);
|
||||||
|
if (!setPhoneResult.Succeeded)
|
||||||
|
{
|
||||||
|
StatusMessage = "Unexpected error when trying to set phone number.";
|
||||||
|
return RedirectToPage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await _signInManager.RefreshSignInAsync(user);
|
||||||
|
StatusMessage = "Your profile has been updated";
|
||||||
|
return RedirectToPage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||||
|
|
||||||
|
namespace WebApp.Areas.Identity.Pages.Account.Manage
|
||||||
|
{
|
||||||
|
public static class ManageNavPages
|
||||||
|
{
|
||||||
|
public static string Index => "Index";
|
||||||
|
|
||||||
|
public static string Email => "Email";
|
||||||
|
|
||||||
|
public static string ChangePassword => "ChangePassword";
|
||||||
|
|
||||||
|
public static string DownloadPersonalData => "DownloadPersonalData";
|
||||||
|
|
||||||
|
public static string DeletePersonalData => "DeletePersonalData";
|
||||||
|
|
||||||
|
public static string ExternalLogins => "ExternalLogins";
|
||||||
|
|
||||||
|
public static string PersonalData => "PersonalData";
|
||||||
|
|
||||||
|
public static string TwoFactorAuthentication => "TwoFactorAuthentication";
|
||||||
|
|
||||||
|
public static string IndexNavClass(ViewContext viewContext) => PageNavClass(viewContext, Index);
|
||||||
|
|
||||||
|
public static string EmailNavClass(ViewContext viewContext) => PageNavClass(viewContext, Email);
|
||||||
|
|
||||||
|
public static string ChangePasswordNavClass(ViewContext viewContext) => PageNavClass(viewContext, ChangePassword);
|
||||||
|
|
||||||
|
public static string DownloadPersonalDataNavClass(ViewContext viewContext) => PageNavClass(viewContext, DownloadPersonalData);
|
||||||
|
|
||||||
|
public static string DeletePersonalDataNavClass(ViewContext viewContext) => PageNavClass(viewContext, DeletePersonalData);
|
||||||
|
|
||||||
|
public static string ExternalLoginsNavClass(ViewContext viewContext) => PageNavClass(viewContext, ExternalLogins);
|
||||||
|
|
||||||
|
public static string PersonalDataNavClass(ViewContext viewContext) => PageNavClass(viewContext, PersonalData);
|
||||||
|
|
||||||
|
public static string TwoFactorAuthenticationNavClass(ViewContext viewContext) => PageNavClass(viewContext, TwoFactorAuthentication);
|
||||||
|
|
||||||
|
private static string PageNavClass(ViewContext viewContext, string page)
|
||||||
|
{
|
||||||
|
var activePage = viewContext.ViewData["ActivePage"] as string
|
||||||
|
?? System.IO.Path.GetFileNameWithoutExtension(viewContext.ActionDescriptor.DisplayName);
|
||||||
|
return string.Equals(activePage, page, StringComparison.OrdinalIgnoreCase) ? "active" : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
@page
|
||||||
|
@model PersonalDataModel
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Personal Data";
|
||||||
|
ViewData["ActivePage"] = ManageNavPages.PersonalData;
|
||||||
|
}
|
||||||
|
|
||||||
|
<h4>@ViewData["Title"]</h4>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<p>Your account contains personal data that you have given us. This page allows you to download or delete that data.</p>
|
||||||
|
<p>
|
||||||
|
<strong>Deleting this data will permanently remove your account, and this cannot be recovered.</strong>
|
||||||
|
</p>
|
||||||
|
<form id="download-data" asp-page="DownloadPersonalData" method="post" class="form-group">
|
||||||
|
<button class="btn btn-primary" type="submit">Download</button>
|
||||||
|
</form>
|
||||||
|
<p>
|
||||||
|
<a id="delete" asp-page="DeletePersonalData" class="btn btn-secondary">Delete</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
|
<partial name="_ValidationScriptsPartial" />
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using Data.Entities;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace WebApp.Areas.Identity.Pages.Account.Manage
|
||||||
|
{
|
||||||
|
public class PersonalDataModel : PageModel
|
||||||
|
{
|
||||||
|
private readonly UserManager<User> _userManager;
|
||||||
|
private readonly ILogger<PersonalDataModel> _logger;
|
||||||
|
|
||||||
|
public PersonalDataModel(
|
||||||
|
UserManager<User> userManager,
|
||||||
|
ILogger<PersonalDataModel> logger)
|
||||||
|
{
|
||||||
|
_userManager = userManager;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IActionResult> OnGet()
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Page();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
@page
|
||||||
|
@model SetPasswordModel
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Set password";
|
||||||
|
ViewData["ActivePage"] = ManageNavPages.ChangePassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
<h4>Set your password</h4>
|
||||||
|
<partial name="_StatusMessage" for="StatusMessage" />
|
||||||
|
<p class="text-info">
|
||||||
|
You do not have a local username/password for this site. Add a local
|
||||||
|
account so you can log in without an external login.
|
||||||
|
</p>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<form id="set-password-form" method="post">
|
||||||
|
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Input.NewPassword"></label>
|
||||||
|
<input asp-for="Input.NewPassword" class="form-control" />
|
||||||
|
<span asp-validation-for="Input.NewPassword" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Input.ConfirmPassword"></label>
|
||||||
|
<input asp-for="Input.ConfirmPassword" class="form-control" />
|
||||||
|
<span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary">Set password</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
|
<partial name="_ValidationScriptsPartial" />
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Data.Entities;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
|
|
||||||
|
namespace WebApp.Areas.Identity.Pages.Account.Manage
|
||||||
|
{
|
||||||
|
public class SetPasswordModel : PageModel
|
||||||
|
{
|
||||||
|
private readonly UserManager<User> _userManager;
|
||||||
|
private readonly SignInManager<User> _signInManager;
|
||||||
|
|
||||||
|
public SetPasswordModel(
|
||||||
|
UserManager<User> userManager,
|
||||||
|
SignInManager<User> signInManager)
|
||||||
|
{
|
||||||
|
_userManager = userManager;
|
||||||
|
_signInManager = signInManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BindProperty]
|
||||||
|
public InputModel Input { get; set; }
|
||||||
|
|
||||||
|
[TempData]
|
||||||
|
public string StatusMessage { get; set; }
|
||||||
|
|
||||||
|
public class InputModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
|
||||||
|
[DataType(DataType.Password)]
|
||||||
|
[Display(Name = "New password")]
|
||||||
|
public string NewPassword { get; set; }
|
||||||
|
|
||||||
|
[DataType(DataType.Password)]
|
||||||
|
[Display(Name = "Confirm new password")]
|
||||||
|
[Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
|
||||||
|
public string ConfirmPassword { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IActionResult> OnGetAsync()
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var hasPassword = await _userManager.HasPasswordAsync(user);
|
||||||
|
|
||||||
|
if (hasPassword)
|
||||||
|
{
|
||||||
|
return RedirectToPage("./ChangePassword");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Page();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IActionResult> OnPostAsync()
|
||||||
|
{
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
return Page();
|
||||||
|
}
|
||||||
|
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var addPasswordResult = await _userManager.AddPasswordAsync(user, Input.NewPassword);
|
||||||
|
if (!addPasswordResult.Succeeded)
|
||||||
|
{
|
||||||
|
foreach (var error in addPasswordResult.Errors)
|
||||||
|
{
|
||||||
|
ModelState.AddModelError(string.Empty, error.Description);
|
||||||
|
}
|
||||||
|
return Page();
|
||||||
|
}
|
||||||
|
|
||||||
|
await _signInManager.RefreshSignInAsync(user);
|
||||||
|
StatusMessage = "Your password has been set.";
|
||||||
|
|
||||||
|
return RedirectToPage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
@{
|
||||||
|
if (ViewData.TryGetValue("ParentLayout", out var parentLayout))
|
||||||
|
{
|
||||||
|
Layout = (string)parentLayout;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Layout = "/Areas/Identity/Pages/_Layout.cshtml";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
<h2>Manage your account</h2>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h4>Change your account settings</h4>
|
||||||
|
<hr />
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-3">
|
||||||
|
<partial name="_ManageNav" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-9">
|
||||||
|
@RenderBody()
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
|
@RenderSection("Scripts", required: false)
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
@inject SignInManager<User> SignInManager
|
||||||
|
@{
|
||||||
|
var hasExternalLogins = (await SignInManager.GetExternalAuthenticationSchemesAsync()).Any();
|
||||||
|
}
|
||||||
|
<ul class="nav nav-pills flex-column">
|
||||||
|
<li class="nav-item"><a class="nav-link @ManageNavPages.IndexNavClass(ViewContext)" id="profile" asp-page="./Index">Profile</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link @ManageNavPages.EmailNavClass(ViewContext)" id="email" asp-page="./Email">Email</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link @ManageNavPages.ChangePasswordNavClass(ViewContext)" id="change-password" asp-page="./ChangePassword">Password</a></li>
|
||||||
|
@if (hasExternalLogins)
|
||||||
|
{
|
||||||
|
<li id="external-logins" class="nav-item"><a id="external-login" class="nav-link @ManageNavPages.ExternalLoginsNavClass(ViewContext)" asp-page="./ExternalLogins">External logins</a></li>
|
||||||
|
}
|
||||||
|
<li class="nav-item"><a class="nav-link @ManageNavPages.TwoFactorAuthenticationNavClass(ViewContext)" id="two-factor" asp-page="./TwoFactorAuthentication">Two-factor authentication</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link @ManageNavPages.PersonalDataNavClass(ViewContext)" id="personal-data" asp-page="./PersonalData">Personal data</a></li>
|
||||||
|
</ul>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
@model string
|
||||||
|
|
||||||
|
@if (!String.IsNullOrEmpty(Model))
|
||||||
|
{
|
||||||
|
var statusMessageClass = Model.StartsWith("Error") ? "danger" : "success";
|
||||||
|
<div class="alert alert-@statusMessageClass alert-dismissible" role="alert">
|
||||||
|
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
@Model
|
||||||
|
</div>
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
@using WebApp.Areas.Identity.Pages.Account.Manage
|
||||||
@@ -17,36 +17,6 @@
|
|||||||
<input asp-for="Input.Email" class="form-control" />
|
<input asp-for="Input.Email" class="form-control" />
|
||||||
<span asp-validation-for="Input.Email" class="text-danger"></span>
|
<span asp-validation-for="Input.Email" class="text-danger"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
|
||||||
<label asp-for="Input.FirstName"></label>
|
|
||||||
<input asp-for="Input.FirstName" class="form-control" />
|
|
||||||
<span asp-validation-for="Input.FirstName" class="text-danger"></span>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label asp-for="Input.LastName"></label>
|
|
||||||
<input asp-for="Input.LastName" class="form-control" />
|
|
||||||
<span asp-validation-for="Input.LastName" class="text-danger"></span>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label asp-for="Input.IsAdmin"></label>
|
|
||||||
<input asp-for="Input.IsAdmin" class="form-control" />
|
|
||||||
<span asp-validation-for="Input.IsAdmin" class="text-danger"></span>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label asp-for="Input.EGN"></label>
|
|
||||||
<input asp-for="Input.EGN" class="form-control" />
|
|
||||||
<span asp-validation-for="Input.EGN" class="text-danger"></span>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label asp-for="Input.PhoneNumber"></label>
|
|
||||||
<input asp-for="Input.PhoneNumber" class="form-control" />
|
|
||||||
<span asp-validation-for="Input.PhoneNumber" class="text-danger"></span>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label asp-for="Input.UserName"></label>
|
|
||||||
<input asp-for="Input.UserName" class="form-control" />
|
|
||||||
<span asp-validation-for="Input.UserName" class="text-danger"></span>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label asp-for="Input.Password"></label>
|
<label asp-for="Input.Password"></label>
|
||||||
<input asp-for="Input.Password" class="form-control" />
|
<input asp-for="Input.Password" class="form-control" />
|
||||||
|
|||||||
@@ -5,10 +5,9 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Encodings.Web;
|
using System.Text.Encodings.Web;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Data;
|
|
||||||
using Data.Entities;
|
|
||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.AspNetCore.Authentication;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Data.Entities;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
@@ -24,19 +23,19 @@ namespace WebApp.Areas.Identity.Pages.Account
|
|||||||
private readonly SignInManager<User> _signInManager;
|
private readonly SignInManager<User> _signInManager;
|
||||||
private readonly UserManager<User> _userManager;
|
private readonly UserManager<User> _userManager;
|
||||||
private readonly ILogger<RegisterModel> _logger;
|
private readonly ILogger<RegisterModel> _logger;
|
||||||
private readonly RentACarDbContext _rentACartDbContext;
|
private readonly IEmailSender _emailSender;
|
||||||
|
|
||||||
public RegisterModel(
|
public RegisterModel(
|
||||||
UserManager<User> userManager,
|
UserManager<User> userManager,
|
||||||
SignInManager<User> signInManager,
|
SignInManager<User> signInManager,
|
||||||
ILogger<RegisterModel> logger,
|
ILogger<RegisterModel> logger,
|
||||||
RentACarDbContext rentACarDbContext)
|
IEmailSender emailSender)
|
||||||
{
|
{
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_signInManager = signInManager;
|
_signInManager = signInManager;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_rentACartDbContext = rentACarDbContext;
|
_emailSender = emailSender;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BindProperty]
|
[BindProperty]
|
||||||
public InputModel Input { get; set; }
|
public InputModel Input { get; set; }
|
||||||
@@ -52,25 +51,6 @@ namespace WebApp.Areas.Identity.Pages.Account
|
|||||||
[Display(Name = "Email")]
|
[Display(Name = "Email")]
|
||||||
public string Email { get; set; }
|
public string Email { get; set; }
|
||||||
|
|
||||||
[Required]
|
|
||||||
public string UserName { get; set; }
|
|
||||||
|
|
||||||
[Required]
|
|
||||||
public string FirstName { get; set; }
|
|
||||||
|
|
||||||
[Required]
|
|
||||||
public string LastName { get; set; }
|
|
||||||
public bool IsAdmin { get; set; }
|
|
||||||
|
|
||||||
[Required]
|
|
||||||
[StringLength(10, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 10)]
|
|
||||||
public string EGN { get; set; }
|
|
||||||
|
|
||||||
[Required]
|
|
||||||
[DataType(DataType.PhoneNumber)]
|
|
||||||
[StringLength(10, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 10)]
|
|
||||||
public string PhoneNumber { get; set; }
|
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
|
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
|
||||||
[DataType(DataType.Password)]
|
[DataType(DataType.Password)]
|
||||||
@@ -95,23 +75,33 @@ namespace WebApp.Areas.Identity.Pages.Account
|
|||||||
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
|
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
|
||||||
if (ModelState.IsValid)
|
if (ModelState.IsValid)
|
||||||
{
|
{
|
||||||
var user = new User { Id = Guid.NewGuid().ToString(), UserName = Input.UserName, Email = Input.Email, FirstName = Input.FirstName, LastName = Input.LastName, PhoneNumber = Input.PhoneNumber, PersonalNumber = Input.EGN};
|
var user = new User { UserName = Input.Email, Email = Input.Email };
|
||||||
var result = await _userManager.CreateAsync(user, Input.Password);
|
var result = await _userManager.CreateAsync(user, Input.Password);
|
||||||
if (result.Succeeded)
|
if (result.Succeeded)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("User created a new account with password.");
|
_logger.LogInformation("User created a new account with password.");
|
||||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
|
||||||
if (Input.IsAdmin == true)
|
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
||||||
|
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
|
||||||
|
var callbackUrl = Url.Page(
|
||||||
|
"/Account/ConfirmEmail",
|
||||||
|
pageHandler: null,
|
||||||
|
values: new { area = "Identity", userId = user.Id, code = code, returnUrl = returnUrl },
|
||||||
|
protocol: Request.Scheme);
|
||||||
|
|
||||||
|
await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
|
||||||
|
$"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
|
||||||
|
|
||||||
|
if (_userManager.Options.SignIn.RequireConfirmedAccount)
|
||||||
{
|
{
|
||||||
await _userManager.AddToRoleAsync(user, "Admin");
|
return RedirectToPage("RegisterConfirmation", new { email = Input.Email, returnUrl = returnUrl });
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await _userManager.AddToRoleAsync(user, "User");
|
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||||
|
return LocalRedirect(returnUrl);
|
||||||
}
|
}
|
||||||
return LocalRedirect(returnUrl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var error in result.Errors)
|
foreach (var error in result.Errors)
|
||||||
{
|
{
|
||||||
ModelState.AddModelError(string.Empty, error.Description);
|
ModelState.AddModelError(string.Empty, error.Description);
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
@page
|
||||||
|
@model ResetPasswordModel
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Reset password";
|
||||||
|
}
|
||||||
|
|
||||||
|
<h1>@ViewData["Title"]</h1>
|
||||||
|
<h4>Reset your password.</h4>
|
||||||
|
<hr />
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<form method="post">
|
||||||
|
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
|
||||||
|
<input asp-for="Input.Code" type="hidden" />
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Input.Email"></label>
|
||||||
|
<input asp-for="Input.Email" class="form-control" />
|
||||||
|
<span asp-validation-for="Input.Email" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Input.Password"></label>
|
||||||
|
<input asp-for="Input.Password" class="form-control" />
|
||||||
|
<span asp-validation-for="Input.Password" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Input.ConfirmPassword"></label>
|
||||||
|
<input asp-for="Input.ConfirmPassword" class="form-control" />
|
||||||
|
<span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary">Reset</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
|
<partial name="_ValidationScriptsPartial" />
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Data.Entities;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
|
using Microsoft.AspNetCore.WebUtilities;
|
||||||
|
|
||||||
|
namespace WebApp.Areas.Identity.Pages.Account
|
||||||
|
{
|
||||||
|
[AllowAnonymous]
|
||||||
|
public class ResetPasswordModel : PageModel
|
||||||
|
{
|
||||||
|
private readonly UserManager<User> _userManager;
|
||||||
|
|
||||||
|
public ResetPasswordModel(UserManager<User> userManager)
|
||||||
|
{
|
||||||
|
_userManager = userManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BindProperty]
|
||||||
|
public InputModel Input { get; set; }
|
||||||
|
|
||||||
|
public class InputModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
[EmailAddress]
|
||||||
|
public string Email { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
|
||||||
|
[DataType(DataType.Password)]
|
||||||
|
public string Password { get; set; }
|
||||||
|
|
||||||
|
[DataType(DataType.Password)]
|
||||||
|
[Display(Name = "Confirm password")]
|
||||||
|
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
|
||||||
|
public string ConfirmPassword { get; set; }
|
||||||
|
|
||||||
|
public string Code { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public IActionResult OnGet(string code = null)
|
||||||
|
{
|
||||||
|
if (code == null)
|
||||||
|
{
|
||||||
|
return BadRequest("A code must be supplied for password reset.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Input = new InputModel
|
||||||
|
{
|
||||||
|
Code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code))
|
||||||
|
};
|
||||||
|
return Page();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IActionResult> OnPostAsync()
|
||||||
|
{
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
return Page();
|
||||||
|
}
|
||||||
|
|
||||||
|
var user = await _userManager.FindByEmailAsync(Input.Email);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
// Don't reveal that the user does not exist
|
||||||
|
return RedirectToPage("./ResetPasswordConfirmation");
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = await _userManager.ResetPasswordAsync(user, Input.Code, Input.Password);
|
||||||
|
if (result.Succeeded)
|
||||||
|
{
|
||||||
|
return RedirectToPage("./ResetPasswordConfirmation");
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var error in result.Errors)
|
||||||
|
{
|
||||||
|
ModelState.AddModelError(string.Empty, error.Description);
|
||||||
|
}
|
||||||
|
return Page();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
@model string
|
||||||
|
|
||||||
|
@if (!String.IsNullOrEmpty(Model))
|
||||||
|
{
|
||||||
|
var statusMessageClass = Model.StartsWith("Error") ? "danger" : "success";
|
||||||
|
<div class="alert alert-@statusMessageClass alert-dismissible" role="alert">
|
||||||
|
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
@Model
|
||||||
|
</div>
|
||||||
|
}
|
||||||
@@ -2,3 +2,4 @@
|
|||||||
@using WebApp.Areas.Identity
|
@using WebApp.Areas.Identity
|
||||||
@using WebApp.Areas.Identity.Pages
|
@using WebApp.Areas.Identity.Pages
|
||||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
|
@using Data.Entities
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
@{
|
|
||||||
|
@{
|
||||||
Layout = "/Views/Shared/_Layout.cshtml";
|
Layout = "/Views/Shared/_Layout.cshtml";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ using Microsoft.AspNetCore.Mvc.Rendering;
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Data;
|
using Data;
|
||||||
using Data.Entities;
|
using Data.Entities;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
|
||||||
namespace WebApp.Controllers
|
namespace WebApp.Controllers
|
||||||
{
|
{
|
||||||
@@ -44,6 +46,7 @@ namespace WebApp.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GET: Cars/Create
|
// GET: Cars/Create
|
||||||
|
[Authorize(Roles = "Admin")]
|
||||||
public IActionResult Create()
|
public IActionResult Create()
|
||||||
{
|
{
|
||||||
return View();
|
return View();
|
||||||
|
|||||||
@@ -29,8 +29,7 @@ namespace API
|
|||||||
public void ConfigureServices(IServiceCollection services)
|
public void ConfigureServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddDbContext<RentACarDbContext>(options =>
|
services.AddDbContext<RentACarDbContext>(options =>
|
||||||
options.UseSqlServer(
|
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
|
||||||
Configuration.GetConnectionString("DefaultConnection")));
|
|
||||||
services.AddDatabaseDeveloperPageExceptionFilter();
|
services.AddDatabaseDeveloperPageExceptionFilter();
|
||||||
services.AddIdentity<User, IdentityRole>(options =>
|
services.AddIdentity<User, IdentityRole>(options =>
|
||||||
{
|
{
|
||||||
@@ -42,7 +41,10 @@ namespace API
|
|||||||
|
|
||||||
options.User.RequireUniqueEmail = false;
|
options.User.RequireUniqueEmail = false;
|
||||||
})
|
})
|
||||||
|
.AddRoles<IdentityRole>()
|
||||||
|
.AddDefaultUI()
|
||||||
.AddEntityFrameworkStores<RentACarDbContext>();
|
.AddEntityFrameworkStores<RentACarDbContext>();
|
||||||
|
|
||||||
services.AddControllersWithViews();
|
services.AddControllersWithViews();
|
||||||
services.AddRazorPages();
|
services.AddRazorPages();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,10 +7,10 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="5.0.13" />
|
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="5.0.13" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="5.0.12" />
|
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="5.0.15" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="5.0.12" />
|
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="5.0.15" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.12" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.15" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.12">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.15">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user