namespace CSR.WebUI.Pages; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using System.ComponentModel.DataAnnotations; using System.Threading.Tasks; using CSR.Application.Interfaces; using CSR.Domain.Entities; using System.Collections.Generic; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; using System.Security.Claims; public class AuthModel(IUserService userService) : PageModel { private readonly IUserService _userService = userService; [BindProperty] public InputModel Input { get; set; } = new(); public List ErrorMessages { get; set; } = []; public class InputModel { [Required(ErrorMessage = "Username is required.")] [Display(Name = "Username")] [StringLength(32, ErrorMessage = "Username cannot be longer than 32 characters.")] [RegularExpression(@"^[a-zA-Z0-9_]+$", ErrorMessage = "Username can only contain letters, numbers and underscore.")] public string Username { get; set; } = string.Empty; [EmailAddress] [Display(Name = "Email")] public string? Email { get; set; } = string.Empty; [Required(ErrorMessage = "Password is required.")] [DataType(DataType.Password)] [Display(Name = "Password")] public string Password { get; set; } = string.Empty; } public void OnGet() { ErrorMessages.Clear(); } public async Task OnPostLoginAsync() { // Clear any previous registration errors ModelState.Remove("Input.Email"); if (!ModelState.IsValid) { foreach (var modelState in ModelState.Values) { foreach (var e in modelState.Errors) { ErrorMessages.Add(e.ErrorMessage); } } return Page(); } var (user, error) = await _userService.Login(Input.Username, Input.Password); if (user == null) { ErrorMessages.Add(error ?? "Login failed."); Console.WriteLine(error); return Page(); } await SendCookies(user.Username, user.Role.Name); return RedirectToPageBasedOnRole(user); } public async Task OnPostLogoutAsync() { await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); return RedirectToPage("/Index"); // Redirect to home page after logout } public async Task OnPostRegisterAsync() { // Email is required for registration, so add a validation error if it's missing if (string.IsNullOrWhiteSpace(Input.Email)) { ModelState.AddModelError("Input.Email", "Email is required for registration."); } if (!ModelState.IsValid) { foreach (var modelState in ModelState.Values) { foreach (var error in modelState.Errors) { ErrorMessages.Add(error.ErrorMessage); } } return Page(); } var result = await _userService.RegisterNewUser(Input.Username, Input.Email!, Input.Password); if (result.User != null) { await _userService.Login(Input.Username, Input.Password); await SendCookies(result.User.Username, result.User.Role.Name); return RedirectToPageBasedOnRole(result.User); } else { if (result.Errors != null) { ErrorMessages.AddRange(result.Errors); } else { ErrorMessages.Add("An unknown error occurred during registration."); } return Page(); } } private async Task SendCookies(string username, string role) { var claims = new List { new(ClaimTypes.Name, username), new(ClaimTypes.Role, role) }; var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); var claimsPrincipal = new ClaimsPrincipal(claimsIdentity); var authProperties = new AuthenticationProperties { IsPersistent = true, ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(5) }; await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, claimsPrincipal, authProperties); } private RedirectToPageResult RedirectToPageBasedOnRole(User user) { if (user == null || string.IsNullOrWhiteSpace(user.Role.Name)) { return RedirectToPage("/Index"); } return user.Role.Name switch { "Admin" => RedirectToPage("/Admin"), "User" => RedirectToPage("/User"), _ => RedirectToPage("/Index"), }; } }