From 57cc5682a0efe2b790015f77fe9d2e2a0bb6ed87 Mon Sep 17 00:00:00 2001 From: Syndamia Date: Thu, 6 May 2021 21:52:47 +0300 Subject: Added automapper; Implemented user register; Improved some database configurations --- ExamTemplate/Data/Models/Role.cs | 3 ++ ExamTemplate/Data/Models/User.cs | 2 +- ExamTemplate/Data/Repositories/UserRepository.cs | 40 ++++++++++++++++++ .../Services/Configurations/UserMappings.cs | 14 +++++++ .../Services/Models/RegisterUserServiceModel.cs | 10 +++++ ExamTemplate/Services/Services.csproj | 4 ++ ExamTemplate/Services/UserService.cs | 30 ++++++++++++++ ExamTemplate/Web/Configurations/UserMappings.cs | 14 +++++++ ExamTemplate/Web/Controllers/HomeController.cs | 2 +- ExamTemplate/Web/Controllers/UserController.cs | 42 +++++++++++++++++++ .../Web/Models/User/RegisterUserViewModel.cs | 10 +++++ ExamTemplate/Web/Startup.cs | 47 +++++++++++++++++++++- ExamTemplate/Web/Views/User/Register.cshtml | 12 ++++++ ExamTemplate/Web/Web.csproj | 2 + 14 files changed, 229 insertions(+), 3 deletions(-) create mode 100644 ExamTemplate/Data/Repositories/UserRepository.cs create mode 100644 ExamTemplate/Services/Configurations/UserMappings.cs create mode 100644 ExamTemplate/Services/Models/RegisterUserServiceModel.cs create mode 100644 ExamTemplate/Services/UserService.cs create mode 100644 ExamTemplate/Web/Configurations/UserMappings.cs create mode 100644 ExamTemplate/Web/Controllers/UserController.cs create mode 100644 ExamTemplate/Web/Models/User/RegisterUserViewModel.cs create mode 100644 ExamTemplate/Web/Views/User/Register.cshtml diff --git a/ExamTemplate/Data/Models/Role.cs b/ExamTemplate/Data/Models/Role.cs index 94e5c48..9a23f13 100644 --- a/ExamTemplate/Data/Models/Role.cs +++ b/ExamTemplate/Data/Models/Role.cs @@ -8,6 +8,9 @@ namespace ExamTemplate.Data.Models [Table("Roles")] public class Role : IdentityRole { + public static string UserRole = "User"; + public static string AdminRole = "Administrator"; + public List Users { get; set; } = new List(); } } diff --git a/ExamTemplate/Data/Models/User.cs b/ExamTemplate/Data/Models/User.cs index 0c3f4c7..cb96942 100644 --- a/ExamTemplate/Data/Models/User.cs +++ b/ExamTemplate/Data/Models/User.cs @@ -10,6 +10,6 @@ namespace ExamTemplate.Data.Models { public string FirstName { get; set; } public string LastName { get; set; } - public List Roles { get; set; } + public List Roles { get; set; } = new List(); } } diff --git a/ExamTemplate/Data/Repositories/UserRepository.cs b/ExamTemplate/Data/Repositories/UserRepository.cs new file mode 100644 index 0000000..97eb21b --- /dev/null +++ b/ExamTemplate/Data/Repositories/UserRepository.cs @@ -0,0 +1,40 @@ +using System.Threading.Tasks; +using ExamTemplate.Data.Models; +using Microsoft.AspNetCore.Identity; + +namespace ExamTemplate.Data.Repositories +{ + public class UserRepository + { + private readonly TemplateContext _context; + private readonly UserManager _userManager; + private readonly RoleManager _roleManager; + + public UserRepository(TemplateContext templateContext, UserManager userManager, RoleManager roleManager) + { + this._context = templateContext; + this._userManager = userManager; + this._roleManager = roleManager; + } + + public async Task AddAsync(User user, string password) + { + user.PasswordHash = this._userManager.PasswordHasher.HashPassword(user, password); + IdentityResult result = await this._userManager.CreateAsync(user); + + return result.Succeeded; + } + + public async Task AddRoleToUserAsync(User user, string roleName) + { + bool succeeded = (await this._userManager.AddToRoleAsync(user, roleName)).Succeeded; + if (succeeded) + { + user.Roles.Add(await this._roleManager.FindByNameAsync(roleName)); + succeeded = await this._context.SaveChangesAsync() >= 1; + } + + return succeeded; + } + } +} diff --git a/ExamTemplate/Services/Configurations/UserMappings.cs b/ExamTemplate/Services/Configurations/UserMappings.cs new file mode 100644 index 0000000..13c6633 --- /dev/null +++ b/ExamTemplate/Services/Configurations/UserMappings.cs @@ -0,0 +1,14 @@ +using AutoMapper; +using ExamTemplate.Data.Models; +using ExamTemplate.Services.Models; + +namespace ExamTemplate.Services.Configurations +{ + public class UserMappings : Profile + { + public UserMappings() + { + CreateMap(); + } + } +} diff --git a/ExamTemplate/Services/Models/RegisterUserServiceModel.cs b/ExamTemplate/Services/Models/RegisterUserServiceModel.cs new file mode 100644 index 0000000..7a274ae --- /dev/null +++ b/ExamTemplate/Services/Models/RegisterUserServiceModel.cs @@ -0,0 +1,10 @@ +namespace ExamTemplate.Services.Models +{ + public class RegisterUserServiceModel + { + public string FirstName { get; set; } + public string LastName { get; set; } + public string Username { get; set; } + public string Password { get; set; } + } +} diff --git a/ExamTemplate/Services/Services.csproj b/ExamTemplate/Services/Services.csproj index 59fa33e..bac932a 100644 --- a/ExamTemplate/Services/Services.csproj +++ b/ExamTemplate/Services/Services.csproj @@ -5,6 +5,10 @@ + + + + net5.0 diff --git a/ExamTemplate/Services/UserService.cs b/ExamTemplate/Services/UserService.cs new file mode 100644 index 0000000..848edf6 --- /dev/null +++ b/ExamTemplate/Services/UserService.cs @@ -0,0 +1,30 @@ +using System.Threading.Tasks; +using AutoMapper; +using ExamTemplate.Data.Models; +using ExamTemplate.Data.Repositories; +using ExamTemplate.Services.Models; + +namespace ExamTemplate.Services +{ + public class UserService + { + private readonly IMapper _autoMapper; + private readonly UserRepository _userRepository; + + public UserService(IMapper autoMapper, UserRepository userRepository) + { + this._autoMapper = autoMapper; + this._userRepository = userRepository; + } + + public async Task RegisterUserAsync(RegisterUserServiceModel registerUserServiceModel) + { + User user = this._autoMapper.Map(registerUserServiceModel); + + bool userCreateResult = await this._userRepository.AddAsync(user, registerUserServiceModel.Password); + bool addRoleResult = await this._userRepository.AddRoleToUserAsync(user, Role.UserRole); + + return userCreateResult && addRoleResult; + } + } +} diff --git a/ExamTemplate/Web/Configurations/UserMappings.cs b/ExamTemplate/Web/Configurations/UserMappings.cs new file mode 100644 index 0000000..d1a5523 --- /dev/null +++ b/ExamTemplate/Web/Configurations/UserMappings.cs @@ -0,0 +1,14 @@ +using AutoMapper; +using ExamTemplate.Services.Models; +using ExamTemplate.Web.Models.User; + +namespace ExamTemplate.Services.Configurations +{ + public class UserMappings : Profile + { + public UserMappings() + { + CreateMap(); + } + } +} diff --git a/ExamTemplate/Web/Controllers/HomeController.cs b/ExamTemplate/Web/Controllers/HomeController.cs index 9f96a95..39ece9a 100644 --- a/ExamTemplate/Web/Controllers/HomeController.cs +++ b/ExamTemplate/Web/Controllers/HomeController.cs @@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Web.Models; -namespace Web.Controllers +namespace ExamTemplate.Web.Controllers { public class HomeController : Controller { diff --git a/ExamTemplate/Web/Controllers/UserController.cs b/ExamTemplate/Web/Controllers/UserController.cs new file mode 100644 index 0000000..cd472de --- /dev/null +++ b/ExamTemplate/Web/Controllers/UserController.cs @@ -0,0 +1,42 @@ +using ExamTemplate.Services; +using Microsoft.AspNetCore.Mvc; +using ExamTemplate.Web.Models.User; +using AutoMapper; +using ExamTemplate.Services.Models; +using System.Threading.Tasks; + +namespace ExamTemplate.Web.Controllers +{ + public class UserController : Controller + { + private readonly IMapper _autoMapper; + private readonly UserService _userService; + + public UserController(IMapper autoMapper, UserService userService) + { + this._autoMapper = autoMapper; + this._userService = userService; + } + + [HttpGet] + [Route("/Register")] + public IActionResult Register() + { + return View(); + } + + [HttpPost] + [Route("/Register")] + public async Task Register(RegisterUserViewModel registerUserViewModel) + { + RegisterUserServiceModel registerUserServiceModel = this._autoMapper.Map(registerUserViewModel); + + bool result = await this._userService.RegisterUserAsync(registerUserServiceModel); + + if (result) + return RedirectToAction("Index", "Home"); + else + return View(); + } + } +} diff --git a/ExamTemplate/Web/Models/User/RegisterUserViewModel.cs b/ExamTemplate/Web/Models/User/RegisterUserViewModel.cs new file mode 100644 index 0000000..5764bdd --- /dev/null +++ b/ExamTemplate/Web/Models/User/RegisterUserViewModel.cs @@ -0,0 +1,10 @@ +namespace ExamTemplate.Web.Models.User +{ + public class RegisterUserViewModel + { + public string FirstName { get; set; } + public string LastName { get; set; } + public string Username { get; set; } + public string Password { get; set; } + } +} diff --git a/ExamTemplate/Web/Startup.cs b/ExamTemplate/Web/Startup.cs index e66e40a..9c43601 100644 --- a/ExamTemplate/Web/Startup.cs +++ b/ExamTemplate/Web/Startup.cs @@ -1,6 +1,12 @@ +using System; +using System.Linq; using ExamTemplate.Data; +using ExamTemplate.Data.Models; +using ExamTemplate.Data.Repositories; +using ExamTemplate.Services; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -21,10 +27,26 @@ namespace Web public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); + services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); - // Database configuration + /* + * Dependency Injection configuration + */ + + services.AddTransient(); + services.AddTransient(); + + /* + * Database configuration + */ services.AddDbContext(options => options.UseNpgsql(this.Configuration.GetConnectionString("LocalDBConnection"))); + + // Needed for SignInManager and UserManager + services.AddIdentity() + .AddRoles() + .AddEntityFrameworkStores(); + } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. @@ -54,6 +76,29 @@ namespace Web name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); }); + + /* + * Make sure that the database is migrated + * and that the User and Admin role exist in database + */ + + using var serviceScope = app.ApplicationServices.CreateScope(); + using var dbContext = serviceScope.ServiceProvider.GetRequiredService(); + + dbContext.Database.Migrate(); + + var roleManager = (RoleManager)serviceScope.ServiceProvider.GetService(typeof(RoleManager)); + if (!dbContext.Roles.Any(x => x.Name == Role.UserRole)) + { + Role userRole = new() { Name = Role.UserRole }; + roleManager.CreateAsync(userRole).Wait(); + } + if (!dbContext.Roles.Any(x => x.Name == Role.AdminRole)) + { + Role adminRole = new() { Name = Role.AdminRole }; + roleManager.CreateAsync(adminRole).Wait(); + } + } } } diff --git a/ExamTemplate/Web/Views/User/Register.cshtml b/ExamTemplate/Web/Views/User/Register.cshtml new file mode 100644 index 0000000..39e39f2 --- /dev/null +++ b/ExamTemplate/Web/Views/User/Register.cshtml @@ -0,0 +1,12 @@ +@model ExamTemplate.Web.Models.User.RegisterUserViewModel +@{ + ViewData["Title"] = "Register"; +} + +
+ + + + + +
diff --git a/ExamTemplate/Web/Web.csproj b/ExamTemplate/Web/Web.csproj index ef3c865..44c6a7a 100644 --- a/ExamTemplate/Web/Web.csproj +++ b/ExamTemplate/Web/Web.csproj @@ -6,6 +6,8 @@ + + -- cgit v1.2.3