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 System.Linq; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; using System.Security.Claims; using System.Runtime.InteropServices; // If you are using ASP.NET Core Identity for sign-in management, you might need: // using Microsoft.AspNetCore.Identity; // using System.Security.Claims; public class AuthModel(IUserService userService) : PageModel { private readonly IUserService _userService = userService; [BindProperty] public LoginModel LoginInput { get; set; } = new(); [BindProperty] public RegisterModel RegisterInput { get; set; } = new(); public List LoginErrorMessages { get; set; } = []; public List RegisterErrorMessages { get; set; } = []; public class LoginModel { [Required(ErrorMessage = "Username is required.")] [Display(Name = "Username")] public string Username { get; set; } = string.Empty; [Required] [DataType(DataType.Password)] [Display(Name = "Password")] public string Password { get; set; } = string.Empty; } public class RegisterModel { [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.")] [DataType(DataType.Text)] public string Username { get; set; } = string.Empty; [Required(ErrorMessage = "Email is required for registration.")] [EmailAddress] [Display(Name = "Email")] public string Email { get; set; } = string.Empty; [Required] [DataType(DataType.Password)] [Display(Name = "Password")] public string Password { get; set; } = string.Empty; } public void OnGet() { } public async Task OnPostRegisterAsync() { if (!ModelState.IsValid) { RegisterErrorMessages.Add("Please correct the form errors."); return Page(); } // Email is required for registration if (string.IsNullOrWhiteSpace(RegisterInput.Email)) { RegisterErrorMessages.Add("Email is required for registration."); return Page(); } var result = await _userService.RegisterNewUser(RegisterInput.Username, RegisterInput.Email, RegisterInput.Password); if (result.User != null) { // Registration successful await _userService.Login(RegisterInput.Username, RegisterInput.Password); await SendCookies(result.User.Username, result.User.Role.Name); return RedirectToPageBasedOnRole(result.User); } else { if (result.Errors != null) { RegisterErrorMessages.AddRange(result.Errors); } else { RegisterErrorMessages.Add("An unknown error occurred during registration."); } return Page(); } } public async Task OnPostLoginAsync() { if (string.IsNullOrWhiteSpace(LoginInput.Username) || string.IsNullOrWhiteSpace(LoginInput.Password)) { LoginErrorMessages.Add("Username and Password are required."); return Page(); } var (user, error) = await _userService.Login(LoginInput.Username, LoginInput.Password); if (user == null) { LoginErrorMessages.Add(error ?? "Login failed."); return Page(); } await SendCookies(user.Username, user.Role.Name); return RedirectToPageBasedOnRole(user); } 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)) { // Default redirect if role is not defined or user is null return RedirectToPage("/Index"); } return user.Role.Name switch { "Admin" => RedirectToPage("/Admin"), "User" => RedirectToPage("/User"), _ => RedirectToPage("/Index"), }; } }