Работает регистрация, логин и разлогин исполнителя, сделаны проверки на залогиненого пользователя

This commit is contained in:
Никита Потапов 2024-05-29 02:22:44 +04:00
parent 3b067247ad
commit e558327e81
16 changed files with 288 additions and 96 deletions

View File

@ -31,13 +31,20 @@ namespace PolyclinicDatabaseImplement.Implements
public List<UserViewModel> GetFilteredList(UserSearchModel model) public List<UserViewModel> GetFilteredList(UserSearchModel model)
{ {
var elements = GetFullList(); var elements = GetFullList();
foreach (var prop in model.GetType().GetProperties()) if (model.Id != null)
{ {
if (model.GetType().GetProperty(prop.Name)?.GetValue(model, null) != null) elements = elements.Where(x => x.Id == model.Id).ToList();
{ }
elements = elements.Where(x => x.GetType().GetProperty(prop.Name)?.GetValue(x, null) == model.GetType().GetProperty(prop.Name)?.GetValue(model, null)).ToList(); if (!model.Email.IsNullOrEmpty())
} {
} elements = elements.Where(x => x.Email == model.Email).ToList();
}
if (!model.Password.IsNullOrEmpty())
{
elements = elements.Where(x => x.Password == model.Password).ToList();
}
return elements; return elements;
} }

View File

@ -22,6 +22,11 @@ namespace PolyclinicWebAppImplementer.Controllers
[HttpGet] [HttpGet]
public IActionResult Index() public IActionResult Index()
{ {
var currentUser = LoginManager.LogginedUser;
if (currentUser == null)
{
return RedirectToAction("Login", "User");
}
List<CourseViewModel> courses = _courseLogic.ReadList(); List<CourseViewModel> courses = _courseLogic.ReadList();
ViewData["Title"] = "Список курсов"; ViewData["Title"] = "Список курсов";
return View("CoursesList", courses); return View("CoursesList", courses);
@ -30,6 +35,11 @@ namespace PolyclinicWebAppImplementer.Controllers
[HttpPost] [HttpPost]
public IActionResult Add(CourseFormModel model, int[] selectedDiagnoses) public IActionResult Add(CourseFormModel model, int[] selectedDiagnoses)
{ {
var currentUser = LoginManager.LogginedUser;
if (currentUser == null)
{
return RedirectToAction("Login", "User");
}
if (HttpContext.Request.Method == "GET") if (HttpContext.Request.Method == "GET")
{ {
ViewData["Title"] = "Новый курс"; ViewData["Title"] = "Новый курс";
@ -61,6 +71,11 @@ namespace PolyclinicWebAppImplementer.Controllers
[HttpPost] [HttpPost]
public IActionResult Edit(int id, CourseFormModel model, int[] selectedDiagnoses) public IActionResult Edit(int id, CourseFormModel model, int[] selectedDiagnoses)
{ {
var currentUser = LoginManager.LogginedUser;
if (currentUser == null)
{
return RedirectToAction("Login", "User");
}
if (HttpContext.Request.Method == "GET") if (HttpContext.Request.Method == "GET")
{ {
var obj = _courseLogic.ReadElement(new CourseSearchModel { Id = id }); var obj = _courseLogic.ReadElement(new CourseSearchModel { Id = id });
@ -94,6 +109,11 @@ namespace PolyclinicWebAppImplementer.Controllers
[HttpPost] [HttpPost]
public IActionResult Delete(int id) public IActionResult Delete(int id)
{ {
var currentUser = LoginManager.LogginedUser;
if (currentUser == null)
{
return RedirectToAction("Login", "User");
}
var obj = _courseLogic.ReadElement(new CourseSearchModel { Id = id }); var obj = _courseLogic.ReadElement(new CourseSearchModel { Id = id });
if (obj != null) if (obj != null)
{ {

View File

@ -4,6 +4,7 @@ using PolyclinicContracts.BusinessLogicsContracts;
using PolyclinicContracts.SearchModels; using PolyclinicContracts.SearchModels;
using PolyclinicContracts.ViewModels; using PolyclinicContracts.ViewModels;
using PolyclinicWebAppImplementer.Models; using PolyclinicWebAppImplementer.Models;
using System.Net;
namespace PolyclinicWebAppImplementer.Controllers namespace PolyclinicWebAppImplementer.Controllers
{ {
@ -21,8 +22,12 @@ namespace PolyclinicWebAppImplementer.Controllers
[HttpGet] [HttpGet]
public IActionResult Index() public IActionResult Index()
{ {
// TODO выводить только пользовательские диагнозы var currentUser = LoginManager.LogginedUser;
List<DiagnoseViewModel> diagnoses = _diagnoseLogic.ReadList(); if (currentUser == null)
{
return RedirectToAction("Login", "User");
}
List<DiagnoseViewModel> diagnoses = _diagnoseLogic.ReadList(new DiagnoseSearchModel { UserId = currentUser.Id });
ViewData["Title"] = "Список диагнозов"; ViewData["Title"] = "Список диагнозов";
return View("DiagnosesList", diagnoses); return View("DiagnosesList", diagnoses);
} }
@ -31,6 +36,11 @@ namespace PolyclinicWebAppImplementer.Controllers
[HttpPost] [HttpPost]
public IActionResult Add(DiagnoseViewModel model) public IActionResult Add(DiagnoseViewModel model)
{ {
var currentUser = LoginManager.LogginedUser;
if (currentUser == null)
{
return RedirectToAction("Login", "User");
}
if (HttpContext.Request.Method == "GET") if (HttpContext.Request.Method == "GET")
{ {
ViewData["Title"] = "Новый диагноз"; ViewData["Title"] = "Новый диагноз";
@ -38,9 +48,9 @@ namespace PolyclinicWebAppImplementer.Controllers
} }
else else
{ {
// TODO прописать UserId
DiagnoseBindingModel diagnose = new DiagnoseBindingModel DiagnoseBindingModel diagnose = new DiagnoseBindingModel
{ {
UserId = currentUser.Id,
Name = model.Name, Name = model.Name,
Comment = model.Comment, Comment = model.Comment,
DateStartDiagnose = model.DateStartDiagnose, DateStartDiagnose = model.DateStartDiagnose,
@ -48,17 +58,25 @@ namespace PolyclinicWebAppImplementer.Controllers
}; };
_diagnoseLogic.Create(diagnose); _diagnoseLogic.Create(diagnose);
return RedirectToAction("Index"); return RedirectToAction("Index");
} }
} }
[HttpGet] [HttpGet]
[HttpPost] [HttpPost]
public IActionResult Edit(int id, DiagnoseViewModel model) public IActionResult Edit(int id, DiagnoseViewModel model)
{ {
// TODO проверить, что пользователь хочет редактировать свой диагноз (UserId) var currentUser = LoginManager.LogginedUser;
if (currentUser == null)
{
return RedirectToAction("Login", "User");
}
var obj = _diagnoseLogic.ReadElement(new DiagnoseSearchModel { Id = id });
if (obj.UserId != currentUser.Id)
{
return StatusCode(403, "Нельзя редактировать чужой диагноз");
}
if (HttpContext.Request.Method == "GET") if (HttpContext.Request.Method == "GET")
{ {
var obj = _diagnoseLogic.ReadElement(new DiagnoseSearchModel { Id = id });
ViewData["Title"] = "Редактировать диагноз"; ViewData["Title"] = "Редактировать диагноз";
return View("DiagnoseForm", obj); return View("DiagnoseForm", obj);
} }
@ -80,8 +98,16 @@ namespace PolyclinicWebAppImplementer.Controllers
[HttpPost] [HttpPost]
public IActionResult Delete(int id) public IActionResult Delete(int id)
{ {
// TODO проверить, что пользователь хочет удалить свой диагноз (UserId) var currentUser = LoginManager.LogginedUser;
if (currentUser == null)
{
return RedirectToAction("Login", "User");
}
var obj = _diagnoseLogic.ReadElement(new DiagnoseSearchModel { Id = id }); var obj = _diagnoseLogic.ReadElement(new DiagnoseSearchModel { Id = id });
if (obj.UserId != currentUser.Id)
{
return StatusCode(403, "Нельзя удалить чужой диагноз");
}
if (obj != null) if (obj != null)
{ {
_diagnoseLogic.Delete(new DiagnoseBindingModel { Id = obj.Id }); _diagnoseLogic.Delete(new DiagnoseBindingModel { Id = obj.Id });

View File

@ -17,63 +17,12 @@ namespace PolyclinicWebAppImplementer.Controllers
{ {
return View(); return View();
} }
[HttpGet]
[HttpPost]
public IActionResult Course()
{
if (HttpContext.Request.Method == "POST")
{
return Redirect("~/Home/Courses");
}
else
{
return View();
}
}
public IActionResult Courses()
{
return View();
}
public IActionResult Symptom()
{
if (HttpContext.Request.Method == "POST")
{
return Redirect("~/Home/Symptomes");
}
else
{
return View();
}
}
public IActionResult Symptomes()
{
return View();
}
public IActionResult Privacy() public IActionResult Privacy()
{ {
return View(); return View();
} }
[HttpGet]
[HttpPost]
public IActionResult Login()
{
if (HttpContext.Request.Method == "POST")
{
return Redirect("~/");
}
else
{
return View();
}
}
public IActionResult Register()
{
return View();
}
[HttpGet] [HttpGet]
[HttpPost] [HttpPost]
public IActionResult AddRecipeToCourse() public IActionResult AddRecipeToCourse()

View File

@ -20,6 +20,11 @@ namespace PolyclinicWebAppImplementer.Controllers
[HttpGet] [HttpGet]
public IActionResult Index() public IActionResult Index()
{ {
var currentUser = LoginManager.LogginedUser;
if (currentUser == null)
{
return RedirectToAction("Login", "User");
}
List<SymptomViewModel> symptomes = _symptomLogic.ReadList(); List<SymptomViewModel> symptomes = _symptomLogic.ReadList();
ViewData["Title"] = "Список симптомов"; ViewData["Title"] = "Список симптомов";
return View("SymptomesList", symptomes); return View("SymptomesList", symptomes);
@ -28,6 +33,11 @@ namespace PolyclinicWebAppImplementer.Controllers
[HttpPost] [HttpPost]
public IActionResult Add(SymptomFormModel model, int[] selectedDiagnoses) public IActionResult Add(SymptomFormModel model, int[] selectedDiagnoses)
{ {
var currentUser = LoginManager.LogginedUser;
if (currentUser == null)
{
return RedirectToAction("Login", "User");
}
if (HttpContext.Request.Method == "GET") if (HttpContext.Request.Method == "GET")
{ {
ViewData["Title"] = "Новый симптом"; ViewData["Title"] = "Новый симптом";
@ -58,6 +68,11 @@ namespace PolyclinicWebAppImplementer.Controllers
[HttpPost] [HttpPost]
public IActionResult Edit(int id, SymptomFormModel model, int[] selectedDiagnoses) public IActionResult Edit(int id, SymptomFormModel model, int[] selectedDiagnoses)
{ {
var currentUser = LoginManager.LogginedUser;
if (currentUser == null)
{
return RedirectToAction("Login", "User");
}
if (HttpContext.Request.Method == "GET") if (HttpContext.Request.Method == "GET")
{ {
var obj = _symptomLogic.ReadElement(new SymptomSearchModel { Id = id }); var obj = _symptomLogic.ReadElement(new SymptomSearchModel { Id = id });
@ -90,6 +105,11 @@ namespace PolyclinicWebAppImplementer.Controllers
[HttpPost] [HttpPost]
public IActionResult Delete(int id) public IActionResult Delete(int id)
{ {
var currentUser = LoginManager.LogginedUser;
if (currentUser == null)
{
return RedirectToAction("Login", "User");
}
var obj = _symptomLogic.ReadElement(new SymptomSearchModel { Id = id }); var obj = _symptomLogic.ReadElement(new SymptomSearchModel { Id = id });
if (obj != null) if (obj != null)
{ {

View File

@ -0,0 +1,98 @@
using Microsoft.AspNetCore.Mvc;
using PolyclinicContracts.BindingModels;
using PolyclinicContracts.BusinessLogicsContracts;
using PolyclinicContracts.SearchModels;
using PolyclinicDataModels.Enums;
using PolyclinicDataModels.Models;
using PolyclinicWebAppImplementer.Models;
namespace PolyclinicWebAppImplementer.Controllers
{
public class UserController : Controller
{
private readonly IUserLogic _userLogic;
public UserController(IUserLogic userLogic)
{
_userLogic = userLogic;
}
[HttpGet]
[HttpPost]
public IActionResult Login(LoginModel model)
{
var errors = new List<string>();
if (HttpContext.Request.Method == "POST")
{
var user = _userLogic.ReadElement(new UserSearchModel { Email = model.Email, Password = model.Password });
if (user == null)
{
errors.Add("Неверные логин или пароль");
}
else if (user.Role != UserRole.Исполнитель)
{
errors.Add("Пользователь имеет неразрешенную роль");
}
if (errors.Count > 0)
{
model = new LoginModel
{
Errors = errors
};
return View(model);
}
LoginManager.LogginedUser = user;
return RedirectToAction("", "Home");
}
else
{
model = new();
return View(model);
}
}
[HttpGet]
[HttpPost]
public IActionResult Register(RegisterModel model)
{
var errors = new List<string>();
if (HttpContext.Request.Method == "POST")
{
if (_userLogic.ReadElement(new UserSearchModel { Email = model.Email }) != null)
{
errors.Add("Пользователь с таким Email уже есть");
}
if (model.Password != model.ConfirmPassword)
{
errors.Add("Пароли не совпадают");
}
if (errors.Count > 0)
{
model.Errors = errors;
model.Password = string.Empty;
model.ConfirmPassword = string.Empty;
return View(model);
}
var user = new UserBindingModel
{
FIO = model.FIO,
Email = model.Email,
Password = model.Password,
Role = UserRole.Исполнитель
};
_userLogic.Create(user);
return RedirectToAction("Login");
}
else
{
return View(model);
}
}
[HttpPost]
public IActionResult Logout()
{
LoginManager.LogginedUser = null;
return RedirectToAction("Login");
}
}
}

View File

@ -0,0 +1,9 @@
using PolyclinicContracts.ViewModels;
namespace PolyclinicWebAppImplementer
{
public static class LoginManager
{
public static UserViewModel? LogginedUser { get; set; }
}
}

View File

@ -0,0 +1,9 @@
namespace PolyclinicWebAppImplementer.Models
{
public class LoginModel
{
public string Email { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
public List<string> Errors { get; set; } = new();
}
}

View File

@ -0,0 +1,11 @@
namespace PolyclinicWebAppImplementer.Models
{
public class RegisterModel
{
public string FIO { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
public string ConfirmPassword { get; set; } = string.Empty;
public List<string> Errors = new();
}
}

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
@ -18,7 +18,7 @@
<ExcludeFromSingleFile>true</ExcludeFromSingleFile> <ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory> <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content> </Content>
<Content Update="Views\Home\Register.cshtml"> <Content Update="Views\User\Register.cshtml">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile> <ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory> <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content> </Content>

View File

@ -17,6 +17,9 @@ builder.Services.AddTransient<IDiagnoseStorage, DiagnoseStorage>();
builder.Services.AddTransient<ICourseStorage, CourseStorage>(); builder.Services.AddTransient<ICourseStorage, CourseStorage>();
builder.Services.AddTransient<ISymptomStorage, SymptomStorage>(); builder.Services.AddTransient<ISymptomStorage, SymptomStorage>();
builder.Services.AddTransient<IUserStorage, UserStorage>();
builder.Services.AddTransient<IUserLogic, UserLogic>();
builder.Services.AddTransient<IProcedureLogic, ProcedureLogic>(); builder.Services.AddTransient<IProcedureLogic, ProcedureLogic>();
builder.Services.AddTransient<IMedicamentLogic, MedicamentLogic>(); builder.Services.AddTransient<IMedicamentLogic, MedicamentLogic>();
builder.Services.AddTransient<IRecipeLogic, RecipeLogic>(); builder.Services.AddTransient<IRecipeLogic, RecipeLogic>();

View File

@ -0,0 +1,9 @@
namespace PolyclinicWebAppImplementer
{
public enum PageVisible
{
AllowAnyBody = 0,
AllowOnlyAuthorized = 1,
AllowOnlyNotAuthorized = 2,
}
}

View File

@ -2,18 +2,18 @@
{ {
public static class SiteMenuItems public static class SiteMenuItems
{ {
public static (string Controller, string Action, string Title) Index = ("Home", "", "Главная"); public static (string Controller, string Action, string Title, PageVisible Visible) Index = ("Home", "", "Главная", PageVisible.AllowAnyBody);
public static (string Controller, string Action, string Title) Courses = ("Courses", "", "Курсы"); public static (string Controller, string Action, string Title, PageVisible Visible) Courses = ("Courses", "", "Курсы", PageVisible.AllowOnlyAuthorized);
public static (string Controller, string Action, string Title) Diagnoses = ("Diagnoses", "", "Болезни"); public static (string Controller, string Action, string Title, PageVisible Visible) Diagnoses = ("Diagnoses", "", "Болезни", PageVisible.AllowOnlyAuthorized);
public static (string Controller, string Action, string Title) Symptomes = ("Symptomes", "", "Симптомы"); public static (string Controller, string Action, string Title, PageVisible Visible) Symptomes = ("Symptomes", "", "Симптомы", PageVisible.AllowOnlyAuthorized);
public static (string Controller, string Action, string Title) Login = ("Home", "Login", "Вход"); public static (string Controller, string Action, string Title, PageVisible Visible) Login = ("User", "Login", "Вход", PageVisible.AllowOnlyNotAuthorized);
public static (string Controller, string Action, string Title) Register = ("Home", "Register", "Регистрация"); public static (string Controller, string Action, string Title, PageVisible Visible) Register = ("User", "Register", "Регистрация", PageVisible.AllowOnlyNotAuthorized);
public static (string Controller, string Action, string Title) Privacy = ("Home", "Privacy", "Политика приватности"); public static (string Controller, string Action, string Title, PageVisible Visible) Privacy = ("Home", "Privacy", "Политика приватности", PageVisible.AllowAnyBody);
public static (string Controller, string Action, string Title) AddRecipeToCourse = ("Home", "AddRecipeToCourse", "Привязка рецепта"); public static (string Controller, string Action, string Title, PageVisible Visible) AddRecipeToCourse = ("Home", "AddRecipeToCourse", "Привязка рецепта", PageVisible.AllowOnlyAuthorized);
public static (string Controller, string Action, string Title) MedicamentsByDiagnoses = ("Home", "MedicamentsByDiagnoses", "Лекарства по болезням"); public static (string Controller, string Action, string Title, PageVisible Visible) MedicamentsByDiagnoses = ("Home", "MedicamentsByDiagnoses", "Лекарства по болезням", PageVisible.AllowOnlyAuthorized);
public static (string Controller, string Action, string Title) DiagnosesReport = ("Home", "DiagnosesReport", "Отчет по болезням"); public static (string Controller, string Action, string Title, PageVisible Visible) DiagnosesReport = ("Home", "DiagnosesReport", "Отчет по болезням", PageVisible.AllowOnlyAuthorized);
public static List<(string Controller, string Action, string Title)> MenuItemsOrder = new List<(string Controller, string Action, string Title)> public static List<(string Controller, string Action, string Title, PageVisible Visible)> MenuItemsOrder = new List<(string Controller, string Action, string Title, PageVisible Visible)>
{ {
Index, Courses, Diagnoses, Symptomes, Login, Register, AddRecipeToCourse, MedicamentsByDiagnoses, DiagnosesReport Index, Courses, Diagnoses, Symptomes, Login, Register, AddRecipeToCourse, MedicamentsByDiagnoses, DiagnosesReport
}; };

View File

@ -32,19 +32,30 @@
<ul class="navbar-nav flex-grow-1"> <ul class="navbar-nav flex-grow-1">
@foreach (var menuItem in SiteMenuItems.MenuItemsOrder) @foreach (var menuItem in SiteMenuItems.MenuItemsOrder)
{ {
<li class="menu-item"> @if (menuItem.Visible == PageVisible.AllowAnyBody ||
@Html.RouteLink(menuItem.Title, new LoginManager.LogginedUser == null && menuItem.Visible == PageVisible.AllowOnlyNotAuthorized ||
{ LoginManager.LogginedUser != null && menuItem.Visible == PageVisible.AllowOnlyAuthorized)
controller = menuItem.Controller, {
action = menuItem.Action <li class="menu-item">
}, new @Html.RouteLink(menuItem.Title, new
{ {
@class = "nav-link text-dark" + (menuItem.Equals(ViewBag.SelectedSiteMenuItem) ? " fw-bold" : "") controller = menuItem.Controller,
} action = menuItem.Action
) }, new
</li> {
@class = "nav-link text-dark" + (menuItem.Equals(ViewBag.SelectedSiteMenuItem) ? " fw-bold" : "")
}
)
</li>
}
} }
</ul> </ul>
@if(LoginManager.LogginedUser != null)
{
<form method="post" asp-action="Logout" asp-controller="User">
<button class="btn btn-secondary" type="submit">Выйти</button>
</form>
}
</div> </div>
</div> </div>
</nav> </nav>

View File

@ -1,20 +1,27 @@
@{ @model LoginModel
@{
ViewBag.SelectedSiteMenuItem = SiteMenuItems.Login; ViewBag.SelectedSiteMenuItem = SiteMenuItems.Login;
} }
<div class="d-flex w-100 h-100 align-content-center justify-content-center"> <div class="d-flex w-100 h-100 align-content-center justify-content-center">
<form class="d-flex flex-column" id="loginForm"method="post"> <form class="d-flex flex-column" id="loginForm"method="post">
<h4>Вход</h4> <h4>Вход</h4>
@foreach (var item in Model.Errors)
{
<div class="alert alert-danger" role="alert">
@item
</div>
}
<div class="mb-2 d-flex w-100"> <div class="mb-2 d-flex w-100">
<label for="emailInput" class="me-2"> <label for="emailInput" class="me-2">
Email Email
</label> </label>
<input id="emailInput" type="email" name="email" placeholder="mail@example.com" class="w-100"/> <input id="emailInput" required type="email" placeholder="mail@example.com" asp-for="Email" class="w-100"/>
</div> </div>
<div class="mb-2 d-flex w-100"> <div class="mb-2 d-flex w-100">
<label for="passwordInput" class="me-2"> <label for="passwordInput" class="me-2">
Пароль Пароль
</label> </label>
<input id="passwordInput" type="password" name="password" class="w-100"/> <input id="passwordInput" required type="password" asp-for="Password" class="w-100"/>
</div> </div>
<button class="btn btn-outline-primary" type="submit"> <button class="btn btn-outline-primary" type="submit">
Войти Войти

View File

@ -1,26 +1,39 @@
@{ @model RegisterModel
@{
ViewBag.SelectedSiteMenuItem = SiteMenuItems.Register; ViewBag.SelectedSiteMenuItem = SiteMenuItems.Register;
} }
<div class="d-flex w-100 h-100 align-content-center justify-content-center"> <div class="d-flex w-100 h-100 align-content-center justify-content-center">
<form class="d-flex flex-column" id="registerForm" method="post"> <form class="d-flex flex-column" id="registerForm" method="post">
<h4>Регистрация</h4> <h4>Регистрация исполнителя</h4>
@foreach (var item in Model.Errors)
{
<div class="alert alert-danger" role="alert">
@item
</div>
}
<div class="mb-2 d-flex w-100"> <div class="mb-2 d-flex w-100">
<label for="fioInput" class="me-2"> <label for="fioInput" class="me-2">
ФИО ФИО
</label> </label>
<input id="fioInput" name="fio" type="text" placeholder="Иванов Иван Иванович" class="w-100" /> <input id="fioInput" required asp-for="FIO" placeholder="Иванов Иван Иванович" class="w-100" />
</div> </div>
<div class="mb-2 d-flex w-100"> <div class="mb-2 d-flex w-100">
<label for="emailInput" class="me-2"> <label for="emailInput" class="me-2">
Email Email
</label> </label>
<input id="emailInput" type="email" name="email" placeholder="mail@example.com" class="w-100" /> <input id="emailInput" required type="email" asp-for="Email" placeholder="mail@example.com" class="w-100" />
</div> </div>
<div class="mb-2 d-flex w-100"> <div class="mb-2 d-flex w-100">
<label for="passwordInput" class="me-2"> <label for="passwordInput" class="me-2">
Пароль Пароль
</label> </label>
<input id="passwordInput" type="password" name="password" class="w-100" /> <input id="passwordInput" required type="password" asp-for="Password" class="w-100" />
</div>
<div class="mb-2 d-flex w-100">
<label for="confirmPasswordInput" class="me-2">
Повторите пароль
</label>
<input id="confirmPasswordInput" required type="password" asp-for="ConfirmPassword" class="w-100" />
</div> </div>
<button class="btn btn-outline-success" type="submit"> <button class="btn btn-outline-success" type="submit">
Зарегистрироваться Зарегистрироваться