NonInventPurchasingSystem/CPRNIMS.WebApi/Controllers/Account/AnonController.cs
2026-01-20 07:44:30 +08:00

339 lines
15 KiB
C#

using CPRNIMS.Domain.Contracts.Account;
using CPRNIMS.Domain.Services.Account;
using CPRNIMS.Domain.Services;
using CPRNIMS.Infrastructure.Entities.Account;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using CPRNIMS.Infrastructure.Models.Common;
using CPRNIMS.Infrastructure.Models.Account;
using Microsoft.AspNetCore.Hosting;
using CPRNIMS.Infrastructure.Helper;
using CPRNIMS.Infrastructure.Entities.Common;
using CPRNIMS.Infrastructure.ViewModel.Common;
namespace CPRNIMS.WebApi.Controllers.Account
{
public class AnonController : Base.BaseController
{
private readonly SMTPHelper _smtpHelper;
public readonly IForgotPassword _forgotPassword;
public readonly UserManager<ApplicationUser> _userManager;
public readonly SignInManager<ApplicationUser> _signInManager;
public readonly UserClaimsManager _userClaimsManager;
public readonly RoleManager<IdentityRole> _roleManager;
public readonly IControllerAccess _controllerAccess;
public readonly IDepartment _department;
public readonly IConfiguration _config;
public readonly IAccount _account;
public AnonController(ErrorMessageService errorMessageService,
IWebHostEnvironment webHostEnvironment
, SMTPHelper sMTPHelper, IForgotPassword forgotPassword
, UserManager<ApplicationUser> userManager
, SignInManager<ApplicationUser> signInManager
, IConfiguration configuration
, UserClaimsManager userClaimsManager, RoleManager<IdentityRole> roleManager
, IControllerAccess controllerAccess, IDepartment department
, IAccount account) :
base(errorMessageService, webHostEnvironment, configuration)
{
_smtpHelper = sMTPHelper;
_forgotPassword = forgotPassword;
_userManager = userManager;
_signInManager = signInManager;
_userClaimsManager = userClaimsManager;
_roleManager = roleManager;
_controllerAccess = controllerAccess;
_department = department;
_config = configuration;
_account = account;
}
[AllowAnonymous]
[HttpPost("GetToken")]
public async Task<IActionResult> GetToken([FromBody] User model)
{
try
{
var user = await _userManager.FindByNameAsync(model.UserName.ToLower());
var userRoles = await _userManager.GetRolesAsync(user);
var signInResult = await _signInManager.CheckPasswordSignInAsync(user, model.Password, lockoutOnFailure: false);
if (signInResult.Succeeded)
{
var authClaims = new List<Claim>
{ new Claim(ClaimTypes.Name, user.UserName),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
};
foreach (var userRole in userRoles)
{
authClaims.Add(new Claim(ClaimTypes.Role, userRole));
}
var token = GetToken(authClaims);
return Ok(new
{
token = new JwtSecurityTokenHandler().WriteToken(token),
expiration = token.ValidTo
});
}
return BadRequest();
}
catch (Exception ex)
{
var message = ex.InnerException?.ToString() ?? ex.Message.ToString();
await PostErrorMessage(message, " WebApi");
throw;
}
}
[AllowAnonymous]
[HttpPost("login")]
public async Task<IActionResult> Login([FromBody] User model)
{
try
{
var user = await _userManager.FindByNameAsync(model.UserName.ToLower());
if (user != null)
{
var signInResult = await _signInManager.CheckPasswordSignInAsync(user, model.Password, lockoutOnFailure: false);
if (signInResult.Succeeded)
{
if (user.LockoutEnabled == true || user.LockoutEnd != null)
{
await _userManager.SetLockoutEnabledAsync(user, false);
user.LockoutEnd = null;
await _userManager.UpdateAsync(user);
}
// Reset access failed count upon successful login
await _userManager.ResetAccessFailedCountAsync(user);
var userRoles = await _userManager.GetRolesAsync(user);
try
{
var authClaims = new List<Claim> { new Claim(ClaimTypes.Name, user.UserName), new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), };
foreach (var userRole in userRoles)
{
authClaims.Add(new Claim(ClaimTypes.Role, userRole));
}
var token = GetToken(authClaims);
return Ok(new
{
token = new JwtSecurityTokenHandler().WriteToken(token),
expiration = token.ValidTo
});
}
catch (Exception ex)
{
var message = ex.InnerException?.ToString() ?? ex.Message.ToString();
await PostErrorMessage(message, " WebApi");
throw;
}
}
else
{
// Increment access failed count
await _userManager.AccessFailedAsync(user);
// Check if the access failed count reaches a threshold
if (user.AccessFailedCount > 3)
{
await _userManager.SetLockoutEnabledAsync(user, true);
await _userManager.SetLockoutEndDateAsync(user, DateTime.Now.AddMinutes(30)); // Lock the account for 30 minutes (you can adjust as needed)
return BadRequest(new ResponseObject { success = false, statusResponse = "Failed", message = "Account is locked. Please try again after 30 minutes or contact support." });
}
else if (signInResult.IsLockedOut)
{
// Increment access failed count
await _userManager.AccessFailedAsync(user);
return BadRequest(new ResponseObject { success = false,statusResponse = "Failed", message = "Account is locked. Please try again after 30 minutes or contact support." });
}
//If the
else
{
return BadRequest(new ResponseObject { success = false, statusResponse = "Failed", message = "Invalid UserName or Password, please double check!" });
}
}
}
return BadRequest(new ResponseObject { success = false, statusResponse = "Failed", message = "Invalid UserName or Password, please double check!" });
}
catch (Exception ex)
{
var message = ex.InnerException?.ToString() ?? ex.Message.ToString();
await PostErrorMessage(message, " WebApi");
return BadRequest(new ResponseObject { success = false, statusResponse = "Failed", message = message });
}
}
[AllowAnonymous]
[HttpPost("ValidateOTP")]
public async Task<IActionResult> ValidateOTP([FromBody] EmailMessageDetailsVM viewModel)
{
try
{
var otpModel = new Otps
{
OTP = viewModel.OTP,
Email = viewModel.Email,
};
if (String.IsNullOrEmpty(otpModel.Email) || String.IsNullOrEmpty(otpModel.OTP))
{
return NotFound();
}
var isEmailExist = await _userManager.FindByEmailAsync(otpModel.Email.ToLower());
if (isEmailExist != null)
{
bool isOTPValid = await _forgotPassword.ValidateOTP(otpModel);
if (isOTPValid)
{
return Ok(new ResponseObject { messCode = 1, message = "You may proceed now." });
}
return Ok(new ResponseObject { messCode = 0, message = "Your OTP is invalid!." });
}
return NotFound();
}
catch (Exception ex)
{
var message = ex.InnerException?.ToString() ?? ex.Message.ToString();
await PostErrorMessage(message, "ForgotPassWebApi");
throw;
}
}
[AllowAnonymous]
[HttpPost("GetUserByEmail")]
public async Task<IActionResult> GetUserByEmail([FromBody] EmailMessageDetailsVM model)
{
try
{
if (string.IsNullOrEmpty(model.Email))
{
return NotFound();
}
var isEmailExist = await _userManager.FindByEmailAsync(model.Email.ToLower());
if (isEmailExist != null)
{
var otpGenerated = _smtpHelper.GenerateOTP();
var otpDetails = new Otps
{
OTP = otpGenerated,
Email = model.Email,
CreatedBy = model.Email,
CreatedDate = DateTime.Now,
UpdatedBy = model.Email,
UpdatedDate = DateTime.Now,
};
bool isOTPExpired = await _forgotPassword.ValidateOTP(otpDetails);
if (isOTPExpired)
{
otpGenerated = _smtpHelper.GenerateOTP();
}
otpDetails.OTP = otpGenerated;
var message = EMailTemplate("Content/SMTPEmailContent", "ForgotPassword.cshtml");
message = message.Replace("@ViewBag.FullName", isEmailExist.FullName);
message = message.Replace("@ViewBag.OTPCode", otpGenerated);
var messageDetails = new EmailMessageDetailsVM
{
Message = message,
Subject = "CLMS - OTP code for password reset",
SenderEmail = _config["SMTP:SenderEmail"],
DisplayName = _config["SMTP:DisplayName"],
Recipient = model.Email,
Bcc = _config["SMTP:CC"],
CC = _config["SMTP:CC"],
NewPassword = _config["SMTP:Password"],
OutGoingPort = 587,
Server = _config["SMTP:Server"],
UserName = _config["SMTP:UserName"]
};
await _forgotPassword.SaveUpdateOTPAsync(otpDetails, true);
await _forgotPassword.SaveUpdateOTPAsync(otpDetails, false);
await _smtpHelper.SendEmailAsync(messageDetails);
return Ok(new ResponseObject { messCode = 1, message = "You may proceed now." });
}
return NotFound();
}
catch (Exception ex)
{
var message = ex.InnerException?.ToString() ?? ex.Message.ToString();
await PostErrorMessage(message, "ForgotPassWebApi");
throw;
}
}
[AllowAnonymous]
[HttpPut("ChangePassword")]
public async Task<IActionResult> ChangePassword([FromBody] EmailMessageDetailsVM model)
{
try
{
var isEmailExist = await _userManager.FindByEmailAsync(model?.Email);
//If this email is exist then go to 2nd validation
if (isEmailExist != null)
{
var passwordToken = "";
// Check if the Password field is not empty
if (!string.IsNullOrEmpty(model.PasswordHash))
{
// Change the user's password
passwordToken = await _userManager.GeneratePasswordResetTokenAsync(isEmailExist);
var passwordChangeResult = await _userManager.ResetPasswordAsync(isEmailExist, passwordToken, model.PasswordHash);
if (!passwordChangeResult.Succeeded)
{
string passwordErrorMessage = passwordChangeResult.Errors?.FirstOrDefault().Description;
return StatusCode(StatusCodes.Status500InternalServerError, new ResponseObject { messCode = 0, message = passwordErrorMessage });
}
}
var otps = new Otps
{
Email = model.Email,
OTP = model.OTP
};
bool isOTPValid = await _forgotPassword.ValidateOTP(otps);
if (isOTPValid != true)
{
return NotFound(new ResponseObject { IsValid = false, message = "Your OTP is invalid or expired!." });
}
else
{
isEmailExist.UpdatedDate = DateTime.Now;
isEmailExist.UpdatedBy = model.Email;
isEmailExist.LockoutEnabled = false;
isEmailExist.LockoutEnd = null;
isEmailExist.AccessFailedCount = 0;
var result = await _userManager.UpdateAsync(isEmailExist);
if (!result.Succeeded)
{
string errorMessage = result.Errors.FirstOrDefault()?.Description;
return StatusCode(StatusCodes.Status500InternalServerError, new ResponseObject { messCode = 0, message = errorMessage });
}
await _forgotPassword.SaveUpdateOTPAsync(otps, true);
return Ok(new ResponseObject { messCode = 1, message = "Your password has been reset successfully!, please check your email." });
}
}
return NotFound(new ResponseObject { messCode = 0, message = "Email not exist!" });
}
catch (Exception ex)
{
var message = ex.InnerException?.ToString() ?? ex.Message.ToString();
await PostErrorMessage(message, "ForgotPassWebApi");
throw;
}
}
}
}