OnlineSalesAutoCrop/Api/OnlineSalesAutoCrop.CoreAPI.Services/Services/Systems/UserService.cs

2649 lines
120 KiB
C#

using Ease.NetCore.DataAccess;
using Ease.NetCore.DataAccess.SQL;
using Ease.NetCore.Utility;
using OnlineSalesAutoCrop.CoreAPI.Models;
using OnlineSalesAutoCrop.CoreAPI.Models.Global;
using OnlineSalesAutoCrop.CoreAPI.Models.Objects;
using OnlineSalesAutoCrop.CoreAPI.Models.Objects.Setups;
using OnlineSalesAutoCrop.CoreAPI.Models.Objects.Systems;
using OnlineSalesAutoCrop.CoreAPI.Models.Requests.Systems;
using OnlineSalesAutoCrop.CoreAPI.Models.Responses.Systems;
using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Systems;
using Microsoft.Data.SqlClient;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OnlineSalesAutoCrop.CoreAPI.Models.Requests.Integrations;
namespace OnlineSalesAutoCrop.CoreAPI.Services.Services.Systems
{
public class UserService(IOptions<AppSettings> settings, IOptions<MenuSettings> menuSettings) : IUserService
{
private readonly AppSettings _settings = settings?.Value;
private readonly MenuSettings _menuSettings = menuSettings?.Value;
/// <summary>
///
/// </summary>
/// <param name="request"></param>
/// <param name="ipAddress"></param>
/// <param name="checkPwd"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
public async Task<User> LoginAsync(LoginRequest request, string ipAddress, bool checkPwd)
{
User user = new() { LoginId = request.LoginId, LoginStatus = EnumLoginStatus.Unsuccessful };
//try
//{
// string password = EncryptPassword(password: request.Password);
// using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true);
// try
// {
// #region Attendance Login and Valid Ip Address
// if (request.AttendanceLogin && !request.LoginId.ToLower().Equals(User.SuperUser_LoginId))
// {
// string errMsg = string.Empty;
// SqlParameter[] p =
// [
// SqlHelperExtension.CreateInParam(pName: "@IpAddress", pType: SqlDbType.VarChar, pValue: request.IpAddress, size: 20),
// SqlHelperExtension.CreateInParam(pName: "@MacAddress", pType: SqlDbType.VarChar, pValue: request.MacAddress, size: 30),
// SqlHelperExtension.CreateInParam(pName: "@HostName", pType: SqlDbType.VarChar, pValue: request.HostName, size: 100),
// SqlHelperExtension.CreateInParam(pName: "@LoginId", pType: SqlDbType.VarChar, pValue: request.LoginId, size: 50),
// SqlHelperExtension.CreateOutParam(pName: "@ErrMsg", pType: SqlDbType.VarChar, pValue: errMsg, size: 300)
// ];
// _ = tc.ExecuteNonQuerySp(spName: "dbo.IsValidIpOrMacAddress", parameterValues: p);
// errMsg = (p[4] == null || p[4].Value == null || p[4].Value == DBNull.Value) ? string.Empty : Convert.ToString(p[4].Value);
// if (!string.IsNullOrEmpty(errMsg))
// {
// tc.End();
// throw new InvalidOperationException(errMsg);
// }
// }
// #endregion
// bool batchEnabled = false;
// DateTime sysDate = DateTime.Today.Date;
// string appVer = string.Empty, alParams = string.Empty;
// int maxTryCount = 5, lockTime = 1, marMonths = 24, idleTime = 0, timeoutTime = 0, pingTime = 0, bmProcessId = 0, prProcessId = 0;
// #region Read Params from ThisSystem
// using (IDataReader dr = tc.ExecuteReader("SELECT MaxTryCount, LockTime, MarMonths, CAST(GETDATE() as date), AppVersion, AutoLogoutParams, BatchEnabled, BmProcessId, PrProcessId FROM ThisSystem"))
// {
// if (dr.Read())
// {
// maxTryCount = dr.GetInt16(0);
// lockTime = dr.GetInt16(1);
// marMonths = dr.GetInt16(2);
// sysDate = dr.GetDateTime(3);
// appVer = dr.GetString(4);
// alParams = dr.IsDBNull(5) ? string.Empty : dr.GetString(5);
// batchEnabled = !dr.IsDBNull(6) && dr.GetInt16(6) != 0;
// bmProcessId = dr.IsDBNull(7) ? 0 : dr.GetInt16(7);
// prProcessId = dr.IsDBNull(8) ? 0 : dr.GetInt16(8);
// }
// dr.Close();
// }
// if (!string.IsNullOrEmpty(alParams))
// {
// string[] times = alParams.Split(separator: ',', options: StringSplitOptions.RemoveEmptyEntries);
// if (times.Length == 3)
// {
// if (!int.TryParse(times[0], out idleTime))
// idleTime = 0;
// if (!int.TryParse(times[1], out timeoutTime))
// timeoutTime = 0;
// if (!int.TryParse(times[2], out pingTime))
// pingTime = 0;
// }
// }
// if (!request.LoginId.ToLower().Equals(User.SuperUser_LoginId) && !request.AppVersion.Equals(appVer))
// {
// user.UnsuccessfulMsg = appVer;
// user.LoginStatus = EnumLoginStatus.VersionMismatch;
// }
// #endregion
// if (user.LoginStatus != EnumLoginStatus.VersionMismatch)
// {
// #region Read User data using authentication data
// string commandText;
// if (!checkPwd)
// {
// commandText = SQLParser.MakeSQL("SELECT UserId, UserName, Status, MobileNo, EmailAddress, AuthReqAtlogin, AuthMethod,"
// + " AuthKey, AppId, AccessStatus, NeverExpire, LastPasswords, LastPassChgDate, ExpireDate, ThemeName, SchemeName, MenuLayout,"
// + " IsLocked, NextLoginTime, DBOnStartup, DAMultiLogin, ViewOwnTaskOnly, EmployeeId, LoginID, EmployeeCode FROM Users WHERE LoginID=%s", request.LoginId);
// }
// else
// {
// commandText = SQLParser.MakeSQL("SELECT UserId, UserName, Status, MobileNo, EmailAddress, AuthReqAtlogin, AuthMethod,"
// + " AuthKey, AppId, AccessStatus, NeverExpire, LastPasswords, LastPassChgDate, ExpireDate, ThemeName, SchemeName, MenuLayout,"
// + " IsLocked, NextLoginTime, DBOnStartup, DAMultiLogin, ViewOwnTaskOnly, EmployeeId, LoginID, EmployeeCode FROM Users"
// + " WHERE (LoginID=%s OR MobileNo=%s OR EmailAddress=%s) AND Password=%s", request.LoginId, request.LoginId, request.LoginId, password);
// }
// using (IDataReader dr = tc.ExecuteReader(commandText: commandText))
// {
// if (dr.Read())
// {
// user = new User
// {
// Id = dr.GetInt32(0),
// UserName = dr.GetString(1),
// Status = (EnumStatus)dr.GetInt16(2),
// MobileNo = dr.GetString(3),
// EmailAddress = dr.GetString(4),
// AuthRequiredAtLogin = !dr.IsDBNull(5) && dr.GetInt16(5) > 0,
// AuthMethod = (EnumAuthenticationMethod)dr.GetInt16(6),
// AuthKey = dr.IsDBNull(7) ? string.Empty : dr.GetString(7),
// AppId = dr.IsDBNull(8) ? string.Empty : dr.GetString(8),
// AccessStatus = (EnumAccessStatus)dr.GetInt16(9),
// NeverExpires = !dr.IsDBNull(10) && dr.GetInt16(10) > 0,
// LastPasswords = dr.IsDBNull(11) ? string.Empty : dr.GetString(11),
// LastPassChgDate = dr.IsDBNull(12) ? null : dr.GetDateTime(12),
// ExpireDate = dr.IsDBNull(13) ? null : dr.GetDateTime(13),
// ThemeName = dr.IsDBNull(14) ? "yellow" : dr.GetString(14),
// SchemeName = dr.IsDBNull(15) ? "dark" : dr.GetString(15),
// MenuLayout = dr.IsDBNull(16) ? "static" : dr.GetString(16),
// IsLocked = !dr.IsDBNull(17) && dr.GetInt16(17) > 0,
// NextLoginTime = dr.IsDBNull(18) ? null : dr.GetDateTime(18),
// DbOnStartup = dr.GetInt16(19) != 0,
// DisallowMultiLogin = dr.GetInt16(20) != 0,
// ViewOwnTaskOnly = dr.GetInt16(21) != 0,
// EmployeeId = dr.IsDBNull(22) ? null : dr.GetInt32(22),
// LoginId = dr.GetString(23),
// EmployeeCode = dr.IsDBNull(24) ? string.Empty : dr.GetString(24),
// TeamSpaceIds = [],
// IdleTime = idleTime,
// PingTime = pingTime,
// SystemDate = sysDate,
// TimeoutTime = timeoutTime,
// PrProcessId = prProcessId,
// BmProcessId = bmProcessId,
// BatchEnabled = batchEnabled,
// LoginStatus = EnumLoginStatus.Success
// };
// }
// dr.Close();
// user.MinReportDate = marMonths <= 0 ? new DateTime(year: 2015, month: 1, day: 1, hour: 0, minute: 0, second: 0, kind: DateTimeKind.Local) : sysDate.AddMonths(-1 * marMonths);
// }
// #endregion
// #region If the user was locked, try set set unlock if Time expired
// if (!request.LoginId.ToLower().Equals(User.SuperUser_LoginId) && user.IsLocked)
// {
// int isSuccessful = 0;
// SqlParameter[] p =
// [
// SqlHelperExtension.CreateInParam(pName: "@LoginId", pType: SqlDbType.VarChar, pValue: request.LoginId, size: 30),
// SqlHelperExtension.CreateInParam(pName: "@LockTime", pType: SqlDbType.Int, pValue: lockTime),
// SqlHelperExtension.CreateOutParam(pName: "@IsSuccessful", pType: SqlDbType.Int, pValue: isSuccessful),
// ];
// _ = tc.ExecuteNonQuerySp(spName: "dbo.DoUnlockUser", parameterValues: p);
// if (p[2] != null && p[2].Value != null && p[2].Value != DBNull.Value)
// isSuccessful = Convert.ToInt32(p[2].Value);
// if (isSuccessful == 1)
// user.IsLocked = false;
// }
// #endregion
// #region Keep log for unauthrise access and Set user lock if exceeds max try
// if (!request.LoginId.ToLower().Equals(User.SuperUser_LoginId) && maxTryCount > 0 && user.LoginStatus == EnumLoginStatus.Unsuccessful)
// {
// int remainsTry = 0;
// DateTime? nextLoginTime = null;
// string tryLoginInfo = $"{request.LoginId}~{password}~13";
// SqlParameter[] p =
// [
// SqlHelperExtension.CreateInParam(pName: "@LoginId", pType: SqlDbType.VarChar, pValue: request.LoginId, size: 30),
// SqlHelperExtension.CreateInParam(pName: "@TryLoginInfo", pType: SqlDbType.VarChar, pValue: tryLoginInfo, size: 100),
// SqlHelperExtension.CreateInParam(pName: "@IpAddress", pType: SqlDbType.VarChar, pValue: ipAddress, size: 20),
// SqlHelperExtension.CreateInParam(pName: "@MaxTryCount", pType: SqlDbType.SmallInt, pValue: maxTryCount),
// SqlHelperExtension.CreateInParam(pName: "@LockTime", pType: SqlDbType.Int, pValue: lockTime),
// SqlHelperExtension.CreateOutParam(pName: "@RemainingTry", pType: SqlDbType.SmallInt, pValue: remainsTry),
// SqlHelperExtension.CreateOutParam(pName: "@NextLoginTime", pType: SqlDbType.DateTime, pValue: nextLoginTime),
// ];
// _ = tc.ExecuteNonQuerySp(spName: "dbo.LogUnauthorizeAccess", parameterValues: p);
// if (p[5] != null && p[5].Value != null && p[5].Value != DBNull.Value)
// remainsTry = Convert.ToInt32(p[5].Value);
// if (p[6] != null && p[6].Value != null && p[6].Value != DBNull.Value)
// nextLoginTime = Convert.ToDateTime(p[6].Value);
// if (remainsTry <= 0)
// {
// user.IsLocked = true;
// if (lockTime <= 0)
// {
// user.NextLoginTime = nextLoginTime;
// user.UnsuccessfulMsg = "Please contact with Head office to Unlock";
// }
// else
// {
// user.NextLoginTime = nextLoginTime;
// user.UnsuccessfulMsg = $"You can Login after {user.NextLoginTime:dd-MMM-yyyy H:mm:ss}";
// }
// }
// else
// {
// user.UnsuccessfulMsg = $"{remainsTry} More attempt{(remainsTry > 1 ? "s" : "")} remaining";
// }
// }
// #endregion
// #region Generate and Save Otp if Otp is enabled and send thru SMS/Email
// if (user.LoginStatus == EnumLoginStatus.Success && user.Status == EnumStatus.Authorized && (user.AuthMethod == EnumAuthenticationMethod.Email || user.AuthMethod == EnumAuthenticationMethod.MobileSMS))
// {
// string secretKey = $"{user.Id}~{user.LoginId}";
// secretKey = secretKey.EncodeAsBase32String(addPadding: false);
// user.AuthValue = TOtpService.GetCurrentPIN(secretKey: secretKey);
// SetAuthValue(tc: tc, authValue: user.AuthValue, validMinutes: 5, userId: user.Id);
// }
// #endregion
// #region If login successful and user is active read module id for this user
// if (user.LoginStatus == EnumLoginStatus.Success && user.Status == EnumStatus.Authorized && !user.IsLocked)
// {
// int logId = 0;
// DateTime? logoutTime = null;
// SqlParameter[] p =
// [
// SqlHelperExtension.CreateInParam(pName: "@UserId", pType: SqlDbType.Int, pValue: user.Id),
// SqlHelperExtension.CreateInParam(pName: "@IpAddress", pType: SqlDbType.VarChar, pValue: ipAddress, size: 20),
// SqlHelperExtension.CreateInParam(pName: "@AppId", pType: SqlDbType.VarChar, pValue: request.AppId, size: 250),
// SqlHelperExtension.CreateInParam(pName: "@LoginId", pType: SqlDbType.VarChar, pValue: user.LoginId, size: 30),
// SqlHelperExtension.CreateInParam(pName: "@LockTime", pType: SqlDbType.Int, pValue: lockTime),
// SqlHelperExtension.CreateInParam(pName: "@AttendanceLogin", pType: SqlDbType.Int, pValue: request.AttendanceLogin? 1:0),
// SqlHelperExtension.CreateInParam(pName: "@LocalIp", pType: SqlDbType.VarChar, pValue: request.IpAddress, size: 20),
// SqlHelperExtension.CreateInParam(pName: "@MacAddress", pType: SqlDbType.VarChar, pValue: request.MacAddress, size: 30),
// SqlHelperExtension.CreateInParam(pName: "@HostName", pType: SqlDbType.VarChar, pValue: request.HostName, size: 100),
// SqlHelperExtension.CreateInParam(pName: "@LoginRemarks", pType: SqlDbType.VarChar, pValue: request.LoginRemarks, size: 50)
// ];
// using (IDataReader dr = tc.ExecuteReaderSp(spName: "dbo.GetPermissionKeys", parameterValues: p))
// {
// user.ModuleIds = [];
// while (dr.Read())
// {
// string moduleId = dr.GetString(0);
// user.ModuleIds.Add(moduleId);
// logId = dr.GetInt32(1);
// if (dr.GetInt16(2) != 0) //Alow add
// {
// user.ModuleIds.Add($"{moduleId}_1");
// }
// if (dr.GetInt16(3) != 0) //Alow edit
// {
// user.ModuleIds.Add($"{moduleId}_2");
// }
// if (dr.GetInt16(4) != 0) //Allow Delete
// {
// user.ModuleIds.Add($"{moduleId}_3");
// }
// logoutTime = dr.IsDBNull(5) ? null : dr.GetDateTime(5);
// }
// dr.Close();
// }
// user.LogId = logId;
// user.LogoutTime = logoutTime;
// //Read User TeamSpace Ids
// using (IDataReader dr = tc.ExecuteReader("SELECT TeamSpaceId FROM TeamSpaceUsers WHERE UserId=%n", user.Id))
// {
// while (dr.Read())
// {
// user.TeamSpaceIds.Add(dr.GetInt32(0));
// }
// dr.Close();
// }
// //Pending Notification count
// user.NotificationCount = GetPendingNotifCount(tc: tc, userId: user.Id);
// }
// #endregion
// }
// tc.End();
// }
// catch (Exception ie)
// {
// tc?.HandleError();
// throw DBCustomError.GenerateCustomError(ie);
// }
//}
//catch (Exception e)
//{
// throw new InvalidOperationException(e.Message, e);
//}
return user;
}
public async Task<User> IntegrationLoginAsync(IntegrationLoginRequest request, string ipAddress, bool checkPwd)
{
User user = null;
try
{
string password = EncryptPassword(password: request.Password);
using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true);
try
{
DateTime sysDate = DateTime.Today.Date;
string appVer = string.Empty, alParams = string.Empty;
int maxTryCount = 5, lockTime = 1;
#region Read User data using authentication data
string commandText = SQLParser.MakeSQL("SELECT UserId,Password,LoginId, UserName, Status, MobileNo, EmailAddress,"
+ " AuthKey, AuthValue, IsLocked FROM Users WHERE LoginID=%s", request.LoginId);
using (IDataReader dr = tc.ExecuteReader(commandText: commandText))
{
if (dr.Read())
{
user = new User
{
UserId = dr.GetInt32(0),
Password = dr.GetString(1),
LoginId = dr.GetString(2),
UserName = dr.GetString(3),
Status = (EnumStatus)dr.GetInt32(4),
MobileNo = dr.GetString(5),
EmailAddress = dr.GetString(6),
AuthKey = dr.GetString(7),
AuthValue = dr.GetString(8),
IsLocked = dr.GetBoolean(9),
LoginStatus = EnumLoginStatus.Success
};
}
dr.Close();
}
if (user is null)
{
tc.End();
throw new InvalidOperationException($"User not found with login: {request.LoginId}");
}
if (!request.Password.Equals(user.Password))
{
tc.End();
throw new InvalidOperationException($"Password mismatch for login: {request.LoginId}");
}
#endregion
#region If the user was locked, try set set unlock if Time expired
if (!request.LoginId.ToLower().Equals(User.SuperUser_LoginId) && user.IsLocked)
{
int isSuccessful = 0;
SqlParameter[] p =
[
SqlHelperExtension.CreateInParam(pName: "@LoginId", pType: SqlDbType.VarChar, pValue: request.LoginId, size: 30),
SqlHelperExtension.CreateInParam(pName: "@LockTime", pType: SqlDbType.Int, pValue: lockTime),
SqlHelperExtension.CreateOutParam(pName: "@IsSuccessful", pType: SqlDbType.Int, pValue: isSuccessful),
];
_ = tc.ExecuteNonQuerySp(spName: "dbo.DoUnlockUser", parameterValues: p);
if (p[2] != null && p[2].Value != null && p[2].Value != DBNull.Value)
isSuccessful = Convert.ToInt32(p[2].Value);
if (isSuccessful == 1)
user.IsLocked = false;
}
#endregion
#region Keep log for unauthrise access and Set user lock if exceeds max try
if (!request.LoginId.ToLower().Equals(User.SuperUser_LoginId) && maxTryCount > 0 && user.LoginStatus == EnumLoginStatus.Unsuccessful)
{
int remainsTry = 0;
DateTime? nextLoginTime = null;
string tryLoginInfo = $"{request.LoginId}~{password}~13";
SqlParameter[] p =
[
SqlHelperExtension.CreateInParam(pName: "@LoginId", pType: SqlDbType.VarChar, pValue: request.LoginId, size: 30),
SqlHelperExtension.CreateInParam(pName: "@TryLoginInfo", pType: SqlDbType.VarChar, pValue: tryLoginInfo, size: 100),
SqlHelperExtension.CreateInParam(pName: "@IpAddress", pType: SqlDbType.VarChar, pValue: ipAddress, size: 20),
SqlHelperExtension.CreateInParam(pName: "@MaxTryCount", pType: SqlDbType.SmallInt, pValue: maxTryCount),
SqlHelperExtension.CreateInParam(pName: "@LockTime", pType: SqlDbType.Int, pValue: lockTime),
SqlHelperExtension.CreateOutParam(pName: "@RemainingTry", pType: SqlDbType.SmallInt, pValue: remainsTry),
SqlHelperExtension.CreateOutParam(pName: "@NextLoginTime", pType: SqlDbType.DateTime, pValue: nextLoginTime),
];
_ = tc.ExecuteNonQuerySp(spName: "dbo.LogUnauthorizeAccess", parameterValues: p);
if (p[5] != null && p[5].Value != null && p[5].Value != DBNull.Value)
remainsTry = Convert.ToInt32(p[5].Value);
if (p[6] != null && p[6].Value != null && p[6].Value != DBNull.Value)
nextLoginTime = Convert.ToDateTime(p[6].Value);
if (remainsTry <= 0)
{
user.IsLocked = true;
if (lockTime <= 0)
{
user.NextLoginTime = nextLoginTime;
user.UnsuccessfulMsg = "Please contact with Head office to Unlock";
}
else
{
user.NextLoginTime = nextLoginTime;
user.UnsuccessfulMsg = $"You can Login after {user.NextLoginTime:dd-MMM-yyyy H:mm:ss}";
}
}
else
{
user.UnsuccessfulMsg = $"{remainsTry} More attempt{(remainsTry > 1 ? "s" : "")} remaining";
}
}
#endregion
#region If login successful and user is active read module id for this user
if (user.LoginStatus == EnumLoginStatus.Success && user.Status == EnumStatus.Authorized && !user.IsLocked)
{
SqlParameter[] p =
[
SqlHelperExtension.CreateInParam(pName: "@UserId", pType: SqlDbType.Int, pValue: user.UserId),
SqlHelperExtension.CreateInParam(pName: "@IpAddress", pType: SqlDbType.VarChar, pValue: ipAddress, size: 20),
SqlHelperExtension.CreateInParam(pName: "@LoginId", pType: SqlDbType.VarChar, pValue: user.LoginId, size: 30),
SqlHelperExtension.CreateInParam(pName: "@LockTime", pType: SqlDbType.Int, pValue: lockTime),
SqlHelperExtension.CreateInParam(pName: "@LoginTime", pType: SqlDbType.DateTime, pValue: DateTime.Now)
];
_ = await tc.ExecuteNonQuerySpAsync(spName: "dbo.SaveAccessLog", parameterValues: p);
}
#endregion
tc.End();
}
catch (Exception ie)
{
tc?.HandleError();
throw DBCustomError.GenerateCustomError(ie);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
return user;
}
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
public async Task<int> LoadNotificationCountAsync(int userId)
{
int value = 0;
try
{
using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
try
{
value = GetPendingNotifCount(tc: tc, userId: userId);
tc.End();
}
catch (Exception ie)
{
tc?.HandleError();
throw DBCustomError.GenerateCustomError(ie);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
return value;
}
/// <summary>
///
/// </summary>
/// <param name="accountId"></param>
/// <returns></returns>
public async Task<FindAccountResponse> FindAccountAsync(string accountId)
{
FindAccountResponse response = new();
try
{
using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
try
{
using (IDataReader dr = tc.ExecuteReader("SELECT UserID, EmailAddress, MobileNo FROM Users WHERE LoginID=%s OR EmailAddress=%s OR MobileNo=%s", accountId, accountId, accountId))
{
if (dr.Read())
{
response.UserId = dr.GetInt32(0);
response.EmailAddress = dr.GetString(1);
response.PhoneNo = dr.GetString(2);
response.Value = true;
}
dr.Close();
}
tc.End();
if (!response.Value)
{
response.ReturnMessage.Add($"[{accountId}] is not a valid Login Id/Email address/Mobile number.");
}
else
{
if (response.PhoneNo.Length > 8)
response.PhoneNoMasked = string.Concat(response.PhoneNo.AsSpan(0, response.PhoneNo.Length - 8), "*****", response.PhoneNo.AsSpan(response.PhoneNo.Length - 3, 3));
int idx = response.EmailAddress.IndexOf('@');
if (idx != -1)
{
string firstPart = response.EmailAddress[..idx];
if (firstPart.Length >= 5)
firstPart = string.Concat(firstPart.AsSpan(0, firstPart.Length - 5), "*****");
response.EmailAddressMasked = string.Concat(firstPart, response.EmailAddress.AsSpan(idx, response.EmailAddress.Length - idx));
}
}
response.ReturnStatus = 200;
}
catch (Exception ie)
{
tc?.HandleError();
throw DBCustomError.GenerateCustomError(ie);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
return response;
}
/// <summary>
///
/// </summary>
/// <param name="authValue"></param>
/// <param name="userId"></param>
/// <returns></returns>
public async Task<bool> ValidateAuthValueAsync(string authValue, int userId)
{
bool returnValue = false;
try
{
using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true);
try
{
SqlParameter[] p =
[
SqlHelperExtension.CreateInParam(pName: "@AuthValue", pType: SqlDbType.VarChar, pValue: authValue, size: 10),
SqlHelperExtension.CreateInParam(pName: "@UserId", pType: SqlDbType.Int, pValue: userId),
SqlHelperExtension.CreateOutParam(pName: "@Valid", pType: SqlDbType.SmallInt, pValue: 0)
];
_ = tc.ExecuteNonQuerySp(spName: "dbo.ValidateAuthValue", parameterValues: p);
if (p[2].Value != null && p[2].Value != DBNull.Value)
returnValue = Convert.ToInt16(p[2].Value) > 0;
tc.End();
}
catch (Exception ie)
{
tc?.HandleError();
throw DBCustomError.GenerateCustomError(ie);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
return returnValue;
}
/// <summary>
///
/// </summary>
/// <param name="user"></param>
/// <param name="ipAddress"></param>
/// <param name="createdBy"></param>
/// <returns></returns>
public async Task<bool> AddUserAsync(NewUserRequest user, string ipAddress, int createdBy)
{
bool returnValue;
try
{
#region Password Policy if Does not change password on next login
if (user.AccessStatus != EnumAccessStatus.FirstTime)
{
ReadPwdParams(userId: 0, loginId: user.LoginId, enfStgPwd: out bool enfStgPwd, minLen: out short minLen, maxLen: out short maxLen, reservedWords: out string reservedWords);
ValidatePwdPolicies(password: user.Password, minLen: minLen, maxLen: maxLen, enfStgPwd: enfStgPwd, reservedWords: reservedWords);
}
#endregion
int userId = 0;
user.Password = EncryptPassword(password: user.Password);
if (!string.IsNullOrEmpty(user.EmailAddress))
user.EmailAddress = user.EmailAddress.Replace(" ", "");
using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true);
try
{
SqlParameter[] p =
[
SqlHelperExtension.CreateInParam(pName: "@LoginId", pType: SqlDbType.VarChar, pValue: user.LoginId, size: 30),
SqlHelperExtension.CreateInParam(pName: "@UserName", pType: SqlDbType.VarChar, pValue: user.UserName, size: 75),
SqlHelperExtension.CreateInParam(pName: "@Designation", pType: SqlDbType.VarChar, pValue: user.Designation, size: 50),
SqlHelperExtension.CreateInParam(pName: "@Password", pType: SqlDbType.VarChar, pValue: user.Password, size: 75),
SqlHelperExtension.CreateInParam(pName: "@MobileNo", pType: SqlDbType.VarChar, pValue: user.MobileNo, size: 15),
SqlHelperExtension.CreateInParam(pName: "@EmailAddress", pType: SqlDbType.VarChar, pValue: user.EmailAddress, size: 100),
SqlHelperExtension.CreateInParam(pName: "@EmployeeId", pType: SqlDbType.Int, pValue: DataReader.GetNullValue(user.EmployeeId)),
SqlHelperExtension.CreateInParam(pName: "@EmployeeCode", pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(user.EmployeeCode), size: 15),
SqlHelperExtension.CreateInParam(pName: "@AuthReqAtlogin", pType: SqlDbType.SmallInt, pValue: user.AuthReqAtlogin ? 1 : 0),
SqlHelperExtension.CreateInParam(pName: "@AuthMethod", pType: SqlDbType.SmallInt, pValue: user.AuthMethod),
SqlHelperExtension.CreateInParam(pName: "@DBOnStartup", pType: SqlDbType.SmallInt, pValue: user.DbOnStartup ? 1 : 0),
SqlHelperExtension.CreateInParam(pName: "@Status", pType: SqlDbType.SmallInt, pValue: user.Status),
SqlHelperExtension.CreateInParam(pName: "@SeqId", pType: SqlDbType.SmallInt, pValue: user.SeqId),
SqlHelperExtension.CreateInParam(pName: "@CanUseAtnSys", pType: SqlDbType.SmallInt, pValue: user.CanUseAttendanceSystem? 1 : 0),
SqlHelperExtension.CreateInParam(pName: "@ViewToAll", pType: SqlDbType.SmallInt, pValue: user.ViewToAll? 1 : 0),
SqlHelperExtension.CreateInParam(pName: "@AccessStatus", pType: SqlDbType.SmallInt, pValue: user.AccessStatus),
SqlHelperExtension.CreateInParam(pName: "@NeverExpire", pType: SqlDbType.SmallInt, pValue: user.NeverExpire ? 1 : 0),
SqlHelperExtension.CreateInParam(pName: "@DAMultiLogin", pType: SqlDbType.SmallInt, pValue: user.DisallowMultiLogin ? 1 : 0),
SqlHelperExtension.CreateInParam(pName: "@IpAddress", pType: SqlDbType.VarChar, pValue: ipAddress, size: 20),
SqlHelperExtension.CreateInParam(pName: "@CreatedBy", pType: SqlDbType.Int, pValue: createdBy),
SqlHelperExtension.CreateOutParam(pName: "@UserId", pType: SqlDbType.Int, pValue: userId),
];
_ = tc.ExecuteNonQuerySp(spName: "dbo.InsertUser", parameterValues: p);
userId = (p[20]?.Value != null && p[20]?.Value != DBNull.Value) ? Convert.ToInt32(p[20].Value) : 0;
if (user.GroupIds != null && user.GroupIds.Count > 0 && userId > 0)
{
List<int> ownerGroupsIds = [];
if (createdBy == User.SuperUser_Id)
{
ownerGroupsIds.AddRange(user.GroupIds);
}
else
{
using IDataReader dr = tc.ExecuteReader("SELECT GroupId FROM Groups WHERE (CreatedBy=%n OR ViewToAll=1)", createdBy);
while (dr.Read())
{
ownerGroupsIds.Add(dr.GetInt32(0));
}
dr.Close();
}
StringBuilder sb = new();
foreach (int groupId in user.GroupIds)
{
if (!ownerGroupsIds.Contains(groupId))
continue;
sb.Append($"INSERT INTO UserGroups(UserId,GroupId) VALUES({userId},{groupId});");
}
_ = tc.ExecuteNonQuery(commandText: sb.ToString());
}
tc.End();
#region Copy File
try
{
string destFileName = System.IO.Path.Combine(_settings.ProfileImageFolder, $"{userId}.png");
string sourceFileName = System.IO.Path.Combine(_settings.ProfileImageFolder, "default-user.png");
if (System.IO.File.Exists(path: sourceFileName))
{
System.IO.File.Copy(sourceFileName: sourceFileName, destFileName: destFileName);
}
}
catch
{
//Do nothing
}
#endregion
returnValue = true;
}
catch (Exception ie)
{
tc?.HandleError();
throw DBCustomError.GenerateCustomError(ie);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
return returnValue;
}
/// <summary>
///
/// </summary>
/// <param name="user"></param>
/// <param name="ipAddress"></param>
/// <param name="modifiedBy"></param>
/// <returns></returns>
public async Task<bool> EditUserAsync(UserRequest user, string ipAddress, int modifiedBy)
{
bool returnValue = false;
try
{
if (!string.IsNullOrEmpty(user.EmailAddress))
user.EmailAddress = user.EmailAddress.Replace(" ", "");
using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true);
try
{
SqlParameter[] p =
[
SqlHelperExtension.CreateInParam(pName: "@LoginId", pType: SqlDbType.VarChar, pValue: user.LoginId, size: 30),
SqlHelperExtension.CreateInParam(pName: "@UserName", pType: SqlDbType.VarChar, pValue: user.UserName, size: 75),
SqlHelperExtension.CreateInParam(pName: "@Designation", pType: SqlDbType.VarChar, pValue: user.Designation, size: 50),
SqlHelperExtension.CreateInParam(pName: "@MobileNo", pType: SqlDbType.VarChar, pValue: user.MobileNo, size: 15),
SqlHelperExtension.CreateInParam(pName: "@EmailAddress", pType: SqlDbType.VarChar, pValue: user.EmailAddress ?? string.Empty, size: 100),
SqlHelperExtension.CreateInParam(pName: "@AuthReqAtlogin", pType: SqlDbType.SmallInt, pValue: user.AuthReqAtlogin ? 1 : 0),
SqlHelperExtension.CreateInParam(pName: "@AuthMethod", pType: SqlDbType.SmallInt, pValue: user.AuthMethod),
SqlHelperExtension.CreateInParam(pName: "@AuthKey", pType: SqlDbType.VarChar, pValue: user.AuthKey, size: 100),
SqlHelperExtension.CreateInParam(pName: "@DBOnStartup", pType: SqlDbType.SmallInt, pValue: user.DbOnStartup ? 1 : 0),
SqlHelperExtension.CreateInParam(pName: "@Status", pType: SqlDbType.SmallInt, pValue: user.Status),
SqlHelperExtension.CreateInParam(pName: "@SeqId", pType: SqlDbType.SmallInt, pValue: user.SeqId),
SqlHelperExtension.CreateInParam(pName: "@CanUseAtnSys", pType: SqlDbType.SmallInt, pValue: user.CanUseAttendanceSystem? 1 : 0),
SqlHelperExtension.CreateInParam(pName: "@ViewToAll", pType: SqlDbType.SmallInt, pValue: user.ViewToAll? 1 : 0),
SqlHelperExtension.CreateInParam(pName: "@AccessStatus", pType: SqlDbType.SmallInt, pValue: user.AccessStatus),
SqlHelperExtension.CreateInParam(pName: "@NeverExpire", pType: SqlDbType.SmallInt, pValue: user.NeverExpire ? 1 : 0),
SqlHelperExtension.CreateInParam(pName: "@DAMultiLogin", pType: SqlDbType.SmallInt, pValue: user.DisallowMultiLogin ? 1 : 0),
SqlHelperExtension.CreateInParam(pName: "@IpAddress", pType: SqlDbType.VarChar, pValue: ipAddress, size: 20),
SqlHelperExtension.CreateInParam(pName: "@ModifiedBy", pType: SqlDbType.Int, pValue: modifiedBy),
SqlHelperExtension.CreateInParam(pName: "@UserId", pType: SqlDbType.Int, pValue: user.UserId)
];
_ = tc.ExecuteNonQuerySp(spName: "dbo.UpdateUser", parameterValues: p);
if (user.GroupIds != null && user.GroupIds.Count > 0 && user.UserId > 0)
{
List<int> ownerGroupsIds = [];
if (modifiedBy == User.SuperUser_Id)
{
ownerGroupsIds.AddRange(user.GroupIds);
}
else
{
using IDataReader dr = tc.ExecuteReader("SELECT GroupId FROM Groups WHERE (CreatedBy=%n OR ViewToAll=1)", modifiedBy);
while (dr.Read())
{
ownerGroupsIds.Add(dr.GetInt32(0));
}
dr.Close();
}
StringBuilder sb = new();
foreach (int groupId in user.GroupIds)
{
if (!ownerGroupsIds.Contains(groupId))
continue;
sb.Append($"INSERT INTO UserGroups(UserId,GroupId) VALUES({user.UserId},{groupId});");
}
_ = tc.ExecuteNonQuery(commandText: sb.ToString());
}
tc.End();
#region Copy File
try
{
string destFileName = System.IO.Path.Combine(_settings.ProfileImageFolder, $"{user.UserId}.png");
string sourceFileName = System.IO.Path.Combine(_settings.ProfileImageFolder, "default-user.png");
if (System.IO.File.Exists(path: sourceFileName) && !System.IO.File.Exists(path: destFileName))
{
System.IO.File.Copy(sourceFileName: sourceFileName, destFileName: destFileName);
}
}
catch
{
//Do nothing
}
#endregion
returnValue = true;
}
catch (Exception ie)
{
tc?.HandleError();
throw DBCustomError.GenerateCustomError(ie);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
return returnValue;
}
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <param name="deletedBy"></param>
/// <returns></returns>
public async Task<bool> DeleteUserAsync(int userId, int deletedBy)
{
bool returnValue;
try
{
using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true);
try
{
SqlParameter[] p =
[
SqlHelperExtension.CreateInParam(pName: "@DeletedBy", pType: SqlDbType.Int, pValue: deletedBy),
SqlHelperExtension.CreateInParam(pName: "@UserId", pType: SqlDbType.Int, pValue: userId)
];
_ = tc.ExecuteNonQuerySp(spName: "dbo.DeleteUser", parameterValues: p);
tc.End();
#region Delete File
try
{
string fileSpec = System.IO.Path.Combine(_settings.ProfileImageFolder, $"{userId}.png");
if (System.IO.File.Exists(path: fileSpec))
System.IO.File.Delete(path: fileSpec);
}
catch
{
//Do nothing
}
#endregion
returnValue = true;
}
catch (Exception ie)
{
tc?.HandleError();
throw DBCustomError.GenerateCustomError(ie);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
return returnValue;
}
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <param name="loginId"></param>
/// <param name="unlockedBy"></param>
/// <returns></returns>
public async Task<bool> UnlockUserAsync(int userId, string loginId, int unlockedBy)
{
bool returnValue;
try
{
using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true);
try
{
SqlParameter[] p =
[
SqlHelperExtension.CreateInParam(pName: "@UserId", pType: SqlDbType.Int, pValue: userId),
SqlHelperExtension.CreateInParam(pName: "@LoginId", pType: SqlDbType.VarChar, pValue: loginId, size: 30),
SqlHelperExtension.CreateInParam(pName: "@UnlockedBy", pType: SqlDbType.Int, pValue: unlockedBy)
];
_ = tc.ExecuteNonQuerySp(spName: "dbo.UnlockUser", parameterValues: p);
tc.End();
returnValue = true;
}
catch (Exception ie)
{
tc?.HandleError();
throw DBCustomError.GenerateCustomError(ie);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
return returnValue;
}
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <param name="newPassword"></param>
/// <param name="ipAddress"></param>
/// <param name="changedBy"></param>
/// <returns></returns>
public async Task<bool> ResetPasswordAsync(int userId, string newPassword, string ipAddress, int changedBy)
{
bool returnValue = false;
try
{
try
{
newPassword = EncryptPassword(password: newPassword);
using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true);
try
{
SqlParameter[] p =
[
SqlHelperExtension.CreateInParam(pName: "@NewPwd", pType: SqlDbType.VarChar, pValue: newPassword, size: 75),
SqlHelperExtension.CreateInParam(pName: "@LastPwds", pType: SqlDbType.VarChar, pValue: string.Empty, size: 700),
SqlHelperExtension.CreateInParam(pName: "@LastPwdChgDate", pType: SqlDbType.DateTime, pValue: DateTime.Now),
SqlHelperExtension.CreateInParam(pName: "@PwdExpireDate", pType: SqlDbType.DateTime, pValue: DateTime.Now),
SqlHelperExtension.CreateInParam(pName: "@IpAddress", pType: SqlDbType.VarChar, pValue: ipAddress, size: 20),
SqlHelperExtension.CreateInParam(pName: "@UserId", pType: SqlDbType.Int, pValue: userId),
SqlHelperExtension.CreateInParam(pName: "@ChangedBy", pType: SqlDbType.Int, pValue: changedBy),
SqlHelperExtension.CreateInParam(pName: "@ResetPwd", pType: SqlDbType.SmallInt, pValue: 1)
];
_ = tc.ExecuteNonQuerySp(spName: "dbo.UpdateUserPassword", parameterValues: p);
tc.End();
returnValue = true;
}
catch (Exception ie)
{
tc?.HandleError();
throw DBCustomError.GenerateCustomError(ie);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
return returnValue;
}
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <param name="newPassword"></param>
/// <param name="ipAddress"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public async Task<bool> SendPasswordAsync(int userId, string newPassword, string ipAddress)
{
bool returnValue = false;
try
{
newPassword = EncryptPassword(password: newPassword);
using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true);
try
{
SqlParameter[] p =
[
SqlHelperExtension.CreateInParam(pName: "@NewPwd", pType: SqlDbType.VarChar, pValue: newPassword, size: 75),
SqlHelperExtension.CreateInParam(pName: "LastPwds", pType: SqlDbType.VarChar, pValue: string.Empty, size: 700),
SqlHelperExtension.CreateInParam(pName: "@LastPwdChgDate", pType: SqlDbType.DateTime, pValue: DateTime.Now),
SqlHelperExtension.CreateInParam(pName: "@PwdExpireDate", pType: SqlDbType.DateTime, pValue: DateTime.Now),
SqlHelperExtension.CreateInParam(pName: "@IpAddress", pType: SqlDbType.VarChar, pValue: ipAddress, size: 20),
SqlHelperExtension.CreateInParam(pName: "@UserId", pType: SqlDbType.Int, pValue: userId),
SqlHelperExtension.CreateInParam(pName: "@ChangedBy", pType: SqlDbType.Int, pValue: userId),
SqlHelperExtension.CreateInParam(pName: "@ResetPwd", pType: SqlDbType.SmallInt, pValue: 1)
];
_ = tc.ExecuteNonQuerySp(spName: "dbo.UpdateUserPassword", parameterValues: p);
tc.End();
returnValue = true;
}
catch (Exception ie)
{
tc?.HandleError();
throw DBCustomError.GenerateCustomError(ie);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
return returnValue;
}
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <param name="newPassword"></param>
/// <param name="oldPassword"></param>
/// <param name="ipAddress"></param>
/// <param name="changedBy"></param>
/// <returns></returns>
public async Task<bool> ChangePasswordAsync(int userId, string oldPassword, string newPassword, string ipAddress, int changedBy)
{
bool returnValue = false;
try
{
bool loginIdCantPwd = false;
DateTime? lastPassChgDate = null;
List<string> actPwdHistories = [];
Queue<string> pwdHistories = new();
EnumAccessStatus accessStatus = EnumAccessStatus.LoggedOut;
short pwdMinLen = 0, pwdMaxLen = 0, daLastPwds = 0, expiryDays = 0;
bool neverExpire = false, enfStgPwd = false, prvntAtckPwdReuse = false;
string loginId = string.Empty, password = string.Empty, lastPasswords = string.Empty, reservedWords = string.Empty;
#region Reading Data from DB
try
{
using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
try
{
using IDataReader dr = tc.ExecuteReader("SELECT A.LoginId, A.Password, A.LastPasswords, A.LastPassChgDate, A.NeverExpire, A.AccessStatus,"
+ " B.EnfStgPwd, B.PwdMinLen, B.PwdMaxLen, B.ExpiryDays, B.DALastPwds, B.PwdRsvdWords, B.loginIdCantPwd, B.PrvntAtckPwdReuse"
+ " FROM Users A LEFT OUTER JOIN ThisSystem B ON A.UserID=A.UserID WHERE A.UserID=%n", userId);
if (dr.Read())
{
loginId = dr.GetString(0);
password = dr.GetString(1);
lastPasswords = dr.IsDBNull(2) ? string.Empty : dr.GetString(2);
lastPassChgDate = dr.IsDBNull(3) ? null : dr.GetDateTime(3);
neverExpire = !dr.IsDBNull(4) && dr.GetInt16(4) > 0;
accessStatus = (EnumAccessStatus)dr.GetInt16(5);
enfStgPwd = !dr.IsDBNull(6) && dr.GetInt16(6) > 0;
pwdMinLen = dr.IsDBNull(7) ? Convert.ToInt16(0) : dr.GetInt16(7);
pwdMaxLen = dr.IsDBNull(8) ? Convert.ToInt16(30) : dr.GetInt16(8);
expiryDays = dr.IsDBNull(9) ? Convert.ToInt16(0) : dr.GetInt16(9);
daLastPwds = dr.IsDBNull(10) ? Convert.ToInt16(0) : dr.GetInt16(10);
reservedWords = dr.IsDBNull(11) ? string.Empty : dr.GetString(11);
loginIdCantPwd = !dr.IsDBNull(12) && dr.GetInt16(12) != 0;
prvntAtckPwdReuse = !dr.IsDBNull(13) && dr.GetInt16(13) != 0;
}
dr.Close();
tc.End();
if (loginIdCantPwd && !string.IsNullOrEmpty(loginId))
{
reservedWords = string.IsNullOrEmpty(reservedWords) ? loginId : $"{reservedWords},{loginId}";
}
}
catch (Exception ie)
{
tc?.HandleError();
throw DBCustomError.GenerateCustomError(ie);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
#endregion
#region Validation
oldPassword = EncryptPassword(password: oldPassword);
if (!oldPassword.Equals(password))
throw new InvalidOperationException("Old Password does not match with system.");
#region Password Histories
if (!string.IsNullOrEmpty(lastPasswords) && !string.IsNullOrWhiteSpace(lastPasswords))
{
string[] pwds = lastPasswords.Split(',');
foreach (string pwd in pwds)
{
pwdHistories.Enqueue(pwd);
}
}
#endregion
#region Actual Password Histories
string[] pwdsHists = [.. pwdHistories];
if (daLastPwds > 0 && pwdsHists.Length > 0)
{
for (int idx = pwdsHists.Length - 1; idx >= 0; idx--)
{
if (!actPwdHistories.Contains(pwdsHists[idx]) && actPwdHistories.Count <= daLastPwds)
actPwdHistories.Add(pwdsHists[idx]);
}
}
#endregion
if (lastPassChgDate.HasValue && prvntAtckPwdReuse && accessStatus != EnumAccessStatus.FirstTime && lastPassChgDate.Value.Date >= DateTime.Today.Date)
{
throw new InvalidOperationException("Password should be at least one day old to change again.");
}
CheckPasswordHistory(password: newPassword, minLen: pwdMinLen, maxLen: pwdMaxLen, enfStgPwd: enfStgPwd, reservedWords: reservedWords, daLastPwds: daLastPwds, pwdHistories: pwdHistories, actPwdHistories: actPwdHistories);
#endregion
#region Updateing Data
if (pwdHistories.ToArray().Length > 0)
lastPasswords = string.Join(",", [.. pwdHistories]);
DateTime? expireDate = null;
lastPassChgDate = DateTime.Now;
if (!neverExpire && expiryDays > 0)
expireDate = DateTime.Now.AddDays(expiryDays);
try
{
newPassword = EncryptPassword(password: newPassword);
using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true);
try
{
SqlParameter[] p =
[
SqlHelperExtension.CreateInParam(pName: "@NewPwd", pType: SqlDbType.VarChar, pValue: newPassword, size: 75),
SqlHelperExtension.CreateInParam(pName: "@LastPwds", pType: SqlDbType.VarChar, pValue: lastPasswords, size: 700),
SqlHelperExtension.CreateInParam(pName: "@LastPwdChgDate", pType: SqlDbType.DateTime, pValue: lastPassChgDate),
SqlHelperExtension.CreateInParam(pName: "@PwdExpireDate", pType: SqlDbType.DateTime, pValue: expireDate),
SqlHelperExtension.CreateInParam(pName: "@IpAddress", pType: SqlDbType.VarChar, pValue: ipAddress, size: 20),
SqlHelperExtension.CreateInParam(pName: "@UserId", pType: SqlDbType.Int, pValue: userId),
SqlHelperExtension.CreateInParam(pName: "@ChangedBy", pType: SqlDbType.Int, pValue: changedBy),
SqlHelperExtension.CreateInParam(pName: "@ResetPwd", pType: SqlDbType.SmallInt, pValue: 0)
];
_ = tc.ExecuteNonQuerySp(spName: "dbo.UpdateUserPassword", parameterValues: p);
tc.End();
returnValue = true;
}
catch (Exception ie)
{
tc?.HandleError();
throw DBCustomError.GenerateCustomError(ie);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
#endregion
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
return returnValue;
}
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <param name="menuLayout"></param>
/// <param name="themeName"></param>
/// <param name="schemeName"></param>
/// <returns></returns>
public async Task<bool> UpdateMyThemeAsync(int userId, string menuLayout, string themeName, string schemeName)
{
bool returnValue = false;
try
{
try
{
using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true);
try
{
SqlParameter[] p =
[
SqlHelperExtension.CreateInParam(pName: "@MenuLayout", pType: SqlDbType.VarChar, pValue: menuLayout, size: 15),
SqlHelperExtension.CreateInParam(pName: "@ThemeName", pType: SqlDbType.VarChar, pValue: themeName, size: 15),
SqlHelperExtension.CreateInParam(pName: "@SchemeName", pType: SqlDbType.VarChar, pValue: schemeName, size: 10),
SqlHelperExtension.CreateInParam(pName: "@UserId", pType: SqlDbType.Int, pValue: userId)
];
_ = tc.ExecuteNonQuerySp(spName: "dbo.UpdateMyTheme", parameterValues: p);
tc.End();
returnValue = true;
}
catch (Exception ie)
{
tc?.HandleError();
throw DBCustomError.GenerateCustomError(ie);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
return returnValue;
}
/// <summary>
///
/// </summary>
/// <param name="address"></param>
/// <param name="contactNo"></param>
/// <param name="modifiedBy"></param>
/// <param name="emplyeeId"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
public async Task<bool> UpdateMyInfoAsync(string address, string contactNo, int modifiedBy, int emplyeeId)
{
bool returnValue = false;
try
{
try
{
using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true);
try
{
SqlParameter[] p =
[
SqlHelperExtension.CreateInParam(pName: "@Address", pType: SqlDbType.VarChar, pValue: address, size: 120),
SqlHelperExtension.CreateInParam(pName: "@ContactNo", pType: SqlDbType.VarChar, pValue: contactNo, size: 25),
SqlHelperExtension.CreateInParam(pName: "@ModifiedBy", pType: SqlDbType.Int, pValue: modifiedBy),
SqlHelperExtension.CreateInParam(pName: "@EmployeeId", pType: SqlDbType.Int, pValue: emplyeeId)
];
_ = tc.ExecuteNonQuerySp(spName: "dbo.UpdateMyInfo", parameterValues: p);
tc.End();
returnValue = true;
}
catch (Exception ie)
{
tc?.HandleError();
throw DBCustomError.GenerateCustomError(ie);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
return returnValue;
}
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <param name="clientType"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
public async Task<UserAttributesResponse> GetAttributesAsync(int userId, int clientType)
{
UserAttributesResponse response = new() { ReturnStatus = 200 };
try
{
using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
try
{
using (IDataReader dr = tc.ExecuteReader("SELECT LoginId FROM Users WHERE UserId=%n", userId))
{
if (dr.Read())
{
response = new UserAttributesResponse
{
UserId = userId,
LoginId = dr.GetString(0),
ReturnStatus = 200,
UkIds = [],
};
}
dr.Close();
}
#region Client & Projects
if (response.UserId > 0)
{
using IDataReader dr = tc.ExecuteReader($"SELECT ProjectId, ClientId FROM UserClients WHERE UserId=%n AND ProjectId IS {(clientType == 1 ? "NOT " : "")}NULL", response.UserId);
while (dr.Read())
{
string ukId = $"{(dr.IsDBNull(0) ? 0 : dr.GetInt32(0))}|{dr.GetInt32(1)}";
response.UkIds.Add(ukId);
}
dr.Close();
}
response.HasSetup = response.UkIds.Count > 0;
#endregion
tc.End();
}
catch (Exception ie)
{
tc?.HandleError();
throw DBCustomError.GenerateCustomError(ie);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
return response;
}
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <param name="clientType"></param>
/// <param name="ipAddress"></param>
/// <param name="attributeSetBy"></param>
/// <param name="ukIds"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <param name="clientType"></param>
/// <param name="deletedBy"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
public async Task<bool> DeleteAttributesAsync(int userId, int clientType, int deletedBy)
{
bool returnValue;
try
{
using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true);
try
{
SqlParameter[] p =
[
SqlHelperExtension.CreateInParam(pName: "@UserId", pType: SqlDbType.Int, pValue: userId),
SqlHelperExtension.CreateInParam(pName: "@ClientType", pType: SqlDbType.SmallInt, pValue: clientType),
SqlHelperExtension.CreateInParam(pName: "@DeletedBy", pType: SqlDbType.Int, pValue: deletedBy)
];
_ = tc.ExecuteNonQuerySp(spName: "dbo.DeleteUserAttributes", parameterValues: p);
tc.End();
returnValue = true;
}
catch (Exception ie)
{
tc?.HandleError();
throw DBCustomError.GenerateCustomError(ie);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
return returnValue;
}
/// <summary>
///
/// </summary>
/// <param name="request"></param>
/// <param name="userId"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
//public async Task<UserSearchResponse> GetUsersAsync(UserSearchRequest request, int userId)
//{
// UserSearchResponse response = new();
// try
// {
// string andClause = string.Empty;
// if (!string.IsNullOrEmpty(request.Criteria))
// {
// string criteria = request.Criteria.Replace("'", "''");
// andClause = $" AND (LoginID='{criteria}' OR MobileNo='{criteria}' OR EmailAddress='{criteria}' OR UserName LIKE '%{criteria}%' OR Designation LIKE '%{criteria}%')";
// }
// if (request.Status > 0)
// andClause += SQLParser.MakeSQL(" AND Status=%n", request.Status);
// if (request.CheckOwner)
// andClause += SQLParser.MakeSQL(" AND (CreatedBy=%n OR ViewToAll=1)", userId);
// string sortField = request.SortField switch
// {
// "userName" => "UserName",
// "designation" => "Designation",
// "mobileNo" => "MobileNo",
// "emailAddress" => "EmailAddress",
// "statusDetail" => "Status",
// "loginId" => "LoginId",
// _ => "SeqId, LoginId"
// };
// string sortOrder = request.SortOrder switch
// {
// "desc" => "DESC",
// _ => "ASC",
// };
// string commandText = request.Skip + request.PageSize <= 0 ?
// SQLParser.MakeSQL("SELECT UserId, LoginId, UserName, Designation, MobileNo, EmailAddress, Status, SeqId, IsLocked, CanUseAtnSys, Password,"
// + " COUNT(*) OVER() AS TotalRows FROM Users WHERE UserId!=-9%q ORDER BY %q %q", andClause, sortField, sortOrder)
// : SQLParser.MakeSQL("SELECT A.UserId, A.LoginId, A.UserName, A.Designation, A.MobileNo, A.EmailAddress, A.Status, A.SeqId, A.IsLocked,"
// + " A.CanUseAtnSys, A.Password, A.TotalRows FROM(SELECT UserId, LoginId, UserName, Designation, MobileNo, EmailAddress, Status, SeqId,"
// + " IsLocked, CanUseAtnSys, Password, ROW_NUMBER() OVER(ORDER BY %q %q) AS RN, COUNT(*) OVER() AS TotalRows FROM Users WHERE UserId!=-9%q) A"
// + " WHERE A.RN>%n AND A.RN<=%n", sortField, sortOrder, andClause, request.Skip, request.Skip + request.PageSize);
// using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
// try
// {
// int totalRows = 0;
// using IDataReader dr = tc.ExecuteReader(commandText: commandText);
// while (dr.Read())
// {
// UserGetResponse item = new()
// {
// UserId = dr.GetInt32(0),
// LoginId = dr.GetString(1),
// UserName = dr.GetString(2),
// Designation = dr.GetString(3),
// MobileNo = dr.GetString(4),
// EmailAddress = dr.GetString(5),
// Status = (EnumStatus)dr.GetInt16(6),
// SeqId = dr.GetInt16(7),
// IsLocked = !dr.IsDBNull(8) && dr.GetInt16(8) != 0,
// CanUseAttendanceSystem = !dr.IsDBNull(9) && dr.GetInt16(9) != 0,
// };
// totalRows = dr.GetInt32(11);
// }
// dr.Close();
// response.TotalRows = totalRows;
// tc.End();
// response.ReturnStatus = 200;
// }
// catch (Exception ie)
// {
// tc?.HandleError();
// throw DBCustomError.GenerateCustomError(ie);
// }
// }
// catch (Exception e)
// {
// throw new InvalidOperationException(e.Message, e);
// }
// return response;
//}
/// <summary>
///
/// </summary>
/// <param name="teamSpaceIds"></param>
/// <param name="projectId"></param>
/// <param name="userId"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
public async Task<UserBasicInfoResponse> GetUsersByTeamSpaceAsync(string teamSpaceIds, int projectId, int userId)
{
UserBasicInfoResponse response = new();
try
{
using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
try
{
string andClause = string.Empty;
if (userId > 0)
{
andClause = $" AND UserID={userId}";
}
else
{
if (!string.IsNullOrEmpty(teamSpaceIds))
{
andClause = $" AND UserID IN(SELECT UserId FROM TeamSpaceUsers WHERE TeamSpaceId IN({teamSpaceIds}))";
}
if (projectId > 0)
{
andClause += $" AND UserID IN(SELECT UserId FROM TeamSpaceUserProjects WHERE ProjectId={projectId})";
}
}
string commandText = $"SELECT UserID, LoginID, UserName, Designation FROM Users WHERE UserID!={User.SuperUser_Id} AND Status=8{andClause} ORDER BY SeqId, UserName";
using IDataReader dr = tc.ExecuteReader(commandText: commandText);
while (dr.Read())
{
UserBasicInfo item = new()
{
UserId = dr.GetInt32(0),
LoginId = dr.GetString(1),
UserName = dr.GetString(2),
Designation = dr.GetString(3),
};
response.Value.Add(item);
}
dr.Close();
tc.End();
response.ReturnStatus = 200;
}
catch (Exception ie)
{
tc?.HandleError();
throw DBCustomError.GenerateCustomError(ie);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
return response;
}
/// <summary>
///
/// </summary>
/// <param name="applyFilter"></param>
/// <param name="teamSpaceIds"></param>
/// <param name="projectId"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
public async Task<UserBasicInfoResponse> GetUsersBasicAsync(bool applyFilter, string teamSpaceIds, int projectId)
{
UserBasicInfoResponse response = new();
try
{
using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
try
{
string commandText;
if (applyFilter)
{
if (!string.IsNullOrEmpty(teamSpaceIds))
{
commandText = $"SELECT UserID, LoginID, UserName, Designation FROM Users WHERE UserID!={User.SuperUser_Id}"
+ $" AND Status=8 AND UserID IN(SELECT UserId FROM TeamSpaceUsers WHERE TeamSpaceId IN({teamSpaceIds}))";
}
else
{
commandText = $"SELECT UserID, LoginID, UserName, Designation FROM Users WHERE UserID!={User.SuperUser_Id} AND Status=8";
}
if (projectId > 0)
{
commandText += $" AND UserID IN(SELECT UserId FROM UserClients WHERE ProjectID={projectId})";
}
}
else
{
commandText = $"SELECT UserID, LoginID, UserName, Designation FROM Users WHERE UserID!={User.SuperUser_Id} AND Status=8";
}
commandText += " ORDER BY SeqId, UserName";
using IDataReader dr = tc.ExecuteReader(commandText: commandText);
while (dr.Read())
{
UserBasicInfo item = new()
{
UserId = dr.GetInt32(0),
LoginId = dr.GetString(1),
UserName = dr.GetString(2),
Designation = dr.GetString(3),
};
response.Value.Add(item);
}
dr.Close();
tc.End();
response.ReturnStatus = 200;
}
catch (Exception ie)
{
tc?.HandleError();
throw DBCustomError.GenerateCustomError(ie);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
return response;
}
/// <summary>
///
/// </summary>
/// <param name="createdBy"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public async Task<UserForceLogoutResponse> GetForceLogoutUsersAsync(int createdBy)
{
UserForceLogoutResponse response = new();
try
{
using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
try
{
string commandText;
if (createdBy == User.SuperUser_Id)
commandText = $"SELECT UserID, LoginID, UserName FROM Users WHERE UserID!={User.SuperUser_Id} AND Status=8 ORDER BY LoginID";
else
commandText = $"SELECT UserID, LoginID, UserName FROM Users WHERE (CreatedBy={createdBy} OR ViewToAll=1) AND Status=8 ORDER BY LoginID";
using IDataReader dr = tc.ExecuteReader(commandText: commandText);
while (dr.Read())
{
UserForceLogout item = new()
{
UserId = dr.GetInt32(0),
LoginId = dr.GetString(1),
UserName = dr.GetString(2)
};
response.Value.Add(item);
}
dr.Close();
tc.End();
response.ReturnStatus = 200;
}
catch (Exception ie)
{
tc?.HandleError();
throw DBCustomError.GenerateCustomError(ie);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
return response;
}
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
public async Task<UserBasicInfoResponse> GetAttendanceUsersAsync(int userId)
{
UserBasicInfoResponse response = new();
try
{
using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
try
{
string andClause = userId > 0 ? $" AND UserID={userId}" : string.Empty;
using IDataReader dr = tc.ExecuteReader(commandText: $"SELECT UserID, LoginID, UserName, Designation FROM Users WHERE EmployeeId IS NOT NULL AND Status=8{andClause} ORDER BY SeqId, UserName");
while (dr.Read())
{
UserBasicInfo item = new()
{
UserId = dr.GetInt32(0),
LoginId = dr.GetString(1),
UserName = dr.GetString(2),
Designation = dr.GetString(3),
};
response.Value.Add(item);
}
dr.Close();
tc.End();
response.ReturnStatus = 200;
}
catch (Exception ie)
{
tc?.HandleError();
throw DBCustomError.GenerateCustomError(ie);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
return response;
}
/// <summary>
///
/// </summary>
/// <param name="userIds"></param>
/// <param name="ipAddress"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public async Task<bool> ForceLogoutNowAsync(List<int> userIds, string ipAddress)
{
bool returnValue;
try
{
using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true);
try
{
SqlParameter[] p =
[
SqlHelperExtension.CreateInParam(pName: "@UserIDs", pType: SqlDbType.VarChar, pValue: string.Join(",", userIds.ToArray()), size: 8000),
SqlHelperExtension.CreateInParam(pName: "@IpAddress", pType: SqlDbType.VarChar, pValue: ipAddress, size: 20)
];
_ = tc.ExecuteNonQuerySp(spName: "dbo.DoForceLogout", parameterValues: p);
tc.End();
returnValue = true;
}
catch (Exception ie)
{
tc?.HandleError();
throw DBCustomError.GenerateCustomError(ie);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
return returnValue;
}
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
public async Task<UserGetResponse> GetUserAsync(int userId)
{
UserGetResponse response = new() { ReturnStatus = 200 };
try
{
using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
try
{
using (IDataReader dr = tc.ExecuteReader("SELECT LoginId, UserName, Designation, MobileNo, EmailAddress, IsLocked, Status,"
+ " AccessStatus, NeverExpire, AuthReqAtlogin, AuthMethod, DBOnStartup, DAMultiLogin, EmployeeCode, SeqId, CanUseAtnSys, ViewToAll"
+ " FROM Users WHERE UserId=%n", userId))
{
if (dr.Read())
{
response = new UserGetResponse
{
UserId = userId,
LoginId = dr.GetString(0),
UserName = dr.GetString(1),
Designation = dr.GetString(2),
MobileNo = dr.GetString(3),
EmailAddress = dr.GetString(4),
IsLocked = !dr.IsDBNull(5) && dr.GetInt16(5) > 0,
Status = (EnumStatus)dr.GetInt16(6),
AccessStatus = (EnumAccessStatus)dr.GetInt16(7),
NeverExpire = !dr.IsDBNull(8) && dr.GetInt16(8) != 0,
AuthRequiredAtLogin = !dr.IsDBNull(9) && dr.GetInt16(9) != 0,
AuthMethod = (EnumAuthenticationMethod)dr.GetInt16(10),
DbOnStartup = !dr.IsDBNull(11) && dr.GetInt16(11) != 0,
DisallowMultiLogin = !dr.IsDBNull(12) && dr.GetInt16(12) != 0,
EmployeeCode = dr.IsDBNull(13) ? string.Empty : dr.GetString(13),
SeqId = dr.GetInt16(14),
CanUseAttendanceSystem = !dr.IsDBNull(15) && dr.GetInt16(15) != 0,
ViewToAll = !dr.IsDBNull(16) && dr.GetInt16(16) != 0,
ReturnStatus = 200
};
}
dr.Close();
}
response.GroupIds = [];
using (IDataReader dr = tc.ExecuteReader("SELECT GroupId FROM UserGroups WHERE UserID=%n", userId))
{
while (dr.Read())
{
response.GroupIds.Add(dr.GetInt32(0));
}
dr.Close();
}
tc.End();
}
catch (Exception ie)
{
tc?.HandleError();
throw DBCustomError.GenerateCustomError(ie);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
return response;
}
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
public async Task<UserProfileResponse> GetUserProfileAsync(int userId)
{
UserProfileResponse response = new() { ReturnStatus = 200 };
try
{
using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
try
{
int employeeId = 0;
using (IDataReader dr = tc.ExecuteReader("SELECT LoginId, UserName, Designation, LastPassChgDate, ExpireDate, EmployeeId FROM Users WHERE UserId=%n", userId))
{
if (dr.Read())
{
response = new UserProfileResponse
{
UserId = userId,
LoginId = dr.GetString(0),
UserName = dr.GetString(1),
Designation = dr.GetString(2),
PwdLastChangedTime = dr.IsDBNull(3) ? null : dr.GetDateTime(3),
NextPwdDate = dr.IsDBNull(4) ? null : dr.GetDateTime(4),
ReturnStatus = 200
};
employeeId = dr.IsDBNull(5) ? 0 : dr.GetInt32(5);
}
dr.Close();
}
if (employeeId > 0)
{
using IDataReader dr = tc.ExecuteReader("SELECT Address, ContactNo FROM Employees WHERE EmployeeId=%n", employeeId);
if (dr.Read())
{
response.Address = dr.GetString(0);
response.ContactNo = dr.GetString(1);
}
dr.Close();
}
response.LoginHistories = [];
using (IDataReader dr = tc.ExecuteReader("SELECT TOP 10 LoginIPAddress, LoginTime, LogoutIPAddress, LogoutTime"
+ " FROM AccessLog WHERE UserID=%n ORDER BY LoginTime DESC", userId))
{
int slNo = 0;
while (dr.Read())
{
slNo++;
LoginHistory item = new()
{
SlNo = slNo,
LoginIp = dr.GetString(0),
LoginTime = dr.GetDateTime(1),
LogoutIp = dr.IsDBNull(2) ? string.Empty : dr.GetString(2),
LogoutTime = dr.IsDBNull(3) ? null : dr.GetDateTime(3),
};
response.LoginHistories.Add(item: item);
}
dr.Close();
}
tc.End();
}
catch (Exception ie)
{
tc?.HandleError();
throw DBCustomError.GenerateCustomError(ie);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
return response;
}
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
public async Task<MenuResponse> GetUserPermissionsAsync(int userId)
{
MenuResponse response = new() { Item = new() { Items = [] } };
MenuItem pi = new() { Label = "User Profile", Icon = "fa fa-user-md", RouterLink = string.Empty, Items = [] };
pi.Items.Add(new() { Label = "My Profile", Icon = "fa fa-user", RouterLink = "/myprofile" });
pi.Items.Add(new() { Label = "Change My Password", Icon = "fa fa-unlock", RouterLink = "/changemypwd" });
pi.Items.Add(new() { Label = "Change My Theme", Icon = "fa fa-user", RouterLink = "/changemytheme" });
pi.Items.Add(new() { Label = "WhatsApp Message", Icon = "fa fa-whatsapp", RouterLink = "/sendwhatsappmsg" });
pi.Items.Add(new() { Label = "Access Log", Icon = "fa fa-list-alt", RouterLink = "/accesslog" });
response.Item.Items.Add(pi);
List<GroupPermission> pmns = [];
try
{
using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
try
{
SqlParameter[] p = [SqlHelperExtension.CreateInParam(pName: "@UserId", pType: SqlDbType.Int, pValue: userId)];
using IDataReader dr = tc.ExecuteReaderSp(spName: "dbo.GetUserPermissions", parameterValues: p);
while (dr.Read())
{
GroupPermission item = new()
{
ModuleId = dr.GetString(0),
AllowSelect = dr.GetInt16(1) != 0,
AllowAdd = dr.GetInt16(2) != 0,
AllowEdit = dr.GetInt16(3) != 0,
AllowDelete = dr.GetInt16(4) != 0
};
pmns.Add(item);
}
dr.Close();
tc.End();
}
catch (Exception ie)
{
tc?.HandleError();
throw DBCustomError.GenerateCustomError(ie);
}
#region Making Hierarchy
List<GroupPermission> items = [];
List<GroupPermission> fullMenu = GlobalFunctions.BuildMenu();
IEnumerable<GroupPermission> data = fullMenu.Where(x => (string.IsNullOrEmpty(x.ParentId) || string.IsNullOrWhiteSpace(x.ParentId)) && x.Visible && pmns.Where(y => y.AllowSelect).Select(z => z.ModuleId).Contains(x.ModuleId));
foreach (GroupPermission datum in data)
{
MakeHierarchy(parent: datum, data: fullMenu, pmns: pmns);
}
items.AddRange(data);
if (_menuSettings?.MenuItems?.Count > 0)
{
foreach (GroupPermission src in items)
{
MenuItem dst = src.Copy();
dst.Label = _menuSettings.GetItem(src.ModuleId, src.ModuleName).Value;
response.Item.Items.Add(dst);
CopyHierarchy(src: src, dst: dst);
}
}
else
{
foreach (GroupPermission src in items)
{
MenuItem dst = src.Copy();
response.Item.Items.Add(dst);
CopyHierarchy(src: src, dst: dst);
}
}
items.Clear();
#endregion
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
return response;
}
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <param name="canViewLeave"></param>
/// <param name="canViewLate"></param>
/// <param name="canViewClientVisit"></param>
/// <param name="canViewHomeOffice"></param>
/// <param name="viewAll"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
/// <summary>
///
/// </summary>
/// <param name="poId"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <param name="id"></param>
/// <param name="documentOf"></param>
/// <param name="orgFileName"></param>
/// <param name="fileName"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public async Task<bool> UploadDocumentAsync(int userId, int id, int documentOf, string orgFileName, string fileName)
{
bool returnValue = false;
try
{
using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true);
try
{
SqlParameter[] p =
[
SqlHelperExtension.CreateInParam(pName: "@UserID", pType: SqlDbType.Int, pValue: userId),
SqlHelperExtension.CreateInParam(pName: "@Id", pType: SqlDbType.Int, pValue: id),
SqlHelperExtension.CreateInParam(pName: "@DocumentOf", pType: SqlDbType.SmallInt, pValue: documentOf),
SqlHelperExtension.CreateInParam(pName: "@OrgFileName", pType: SqlDbType.VarChar, pValue: orgFileName, size: 200),
SqlHelperExtension.CreateInParam(pName: "@FileName", pType: SqlDbType.VarChar, pValue: fileName, size: 100)
];
_ = tc.ExecuteNonQuerySp(spName: "dbo.UploadDocument", parameterValues: p);
tc.End();
}
catch (Exception ie)
{
tc?.HandleError();
throw DBCustomError.GenerateCustomError(ie);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
return returnValue;
}
/// <summary>
///
/// </summary>
/// <param name="ipAddress"></param>
/// <param name="userId"></param>
/// <param name="logId"></param>
/// <param name="attendanceLogout"></param>
/// <param name="loginId"></param>
/// <param name="localIp"></param>
/// <param name="macAddress"></param>
/// <param name="hostName"></param>
/// <param name="logoutRemarks"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
public async Task<bool> LogoutAsync(string ipAddress, int userId, int logId, bool attendanceLogout, string loginId, string localIp, string macAddress, string hostName, string logoutRemarks)
{
bool returnValue = false;
try
{
using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true);
try
{
SqlParameter[] p;
#region Attendance Logout and Valid Ip Address
if (attendanceLogout && userId != User.SuperUser_Id)
{
string errMsg = string.Empty;
p =
[
SqlHelperExtension.CreateInParam(pName: "@UserID", pType: SqlDbType.Int, pValue: userId),
SqlHelperExtension.CreateInParam(pName: "@LoginId", pType: SqlDbType.VarChar, pValue: loginId, size: 30),
SqlHelperExtension.CreateInParam(pName: "@IpAddress", pType: SqlDbType.VarChar, pValue: localIp, size: 20),
SqlHelperExtension.CreateInParam(pName: "@MacAddress", pType: SqlDbType.VarChar, pValue: macAddress, size: 30),
SqlHelperExtension.CreateInParam(pName: "@HostName", pType: SqlDbType.VarChar, pValue: hostName, size: 100),
SqlHelperExtension.CreateInParam(pName: "@LogoutRemarks", pType: SqlDbType.VarChar, pValue: logoutRemarks, size: 50),
SqlHelperExtension.CreateOutParam(pName: "@ErrMsg", pType: SqlDbType.VarChar, pValue: errMsg, size: 300)
];
_ = tc.ExecuteNonQuerySp(spName: "dbo.LogoutFromAttendance", parameterValues: p);
errMsg = (p[6] == null || p[6].Value == null || p[6].Value == DBNull.Value) ? string.Empty : Convert.ToString(p[6].Value);
if (!string.IsNullOrEmpty(errMsg))
{
throw new InvalidOperationException(errMsg);
}
}
#endregion
//Keep access history
p =
[
SqlHelperExtension.CreateInParam(pName: "@UserID", pType: SqlDbType.Int, pValue: userId),
SqlHelperExtension.CreateInParam(pName: "@Status", pType: SqlDbType.TinyInt, pValue: 3),
SqlHelperExtension.CreateInParam(pName: "@IpAddress", pType: SqlDbType.VarChar, pValue: ipAddress, size: 20),
SqlHelperExtension.CreateInParam(pName: "@LogID", pType: SqlDbType.Int, pValue: logId),
];
_ = tc.ExecuteNonQuerySp(spName: "dbo.CreateAccessLog", parameterValues: p);
tc.End();
}
catch (Exception ie)
{
tc?.HandleError();
throw DBCustomError.GenerateCustomError(ie);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
return returnValue;
}
/// <summary>
///
/// </summary>
/// <param name="accessType"></param>
/// <param name="loginId"></param>
/// <param name="startDate"></param>
/// <param name="endDate"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public async Task<AccessLogResponse> GetAccessLogAsync(int accessType, string loginId, DateTime startDate, DateTime endDate)
{
AccessLogResponse response = new() { Value = [] };
try
{
using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
try
{
SqlParameter[] p =
[
SqlHelperExtension.CreateInParam(pName: "@AccessType", pType: SqlDbType.SmallInt, pValue: accessType),
SqlHelperExtension.CreateInParam(pName: "@LoginID", pType: SqlDbType.VarChar, pValue: loginId, size: 30),
SqlHelperExtension.CreateInParam(pName: "@StartDate", pType: SqlDbType.DateTime, pValue: startDate),
SqlHelperExtension.CreateInParam(pName: "@EndDate", pType: SqlDbType.DateTime, pValue: endDate),
];
using IDataReader dr = tc.ExecuteReaderSp(spName: "dbo.GetAccessLogData", parameterValues: p);
while (dr.Read())
{
AccessLog item = new()
{
LoginId = dr.GetString(0),
LoginTime = dr.GetDateTime(1),
LoginIp = dr.GetString(2),
LogoutTime = dr.IsDBNull(3) ? null : dr.GetDateTime(3),
LogoutIp = dr.IsDBNull(4) ? null : dr.GetString(4)
};
response.Value.Add(item);
}
dr.Close();
tc.End();
response.ReturnStatus = 200;
}
catch (Exception ie)
{
tc?.HandleError();
throw DBCustomError.GenerateCustomError(ie);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
return response;
}
/// <summary>
///
/// </summary>
/// <param name="maxAuthLimit"></param>
/// <param name="userId"></param>
/// <param name="ipAddress"></param>
/// <param name="savedBy"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
public async Task<bool> SaveAuthorizeLimitAsync(decimal maxAuthLimit, int userId, string ipAddress, string savedBy)
{
bool returnValue;
try
{
using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true);
try
{
SqlParameter[] p =
[
SqlHelperExtension.CreateInParam(pName: "@MaxAuthLimit", pType: SqlDbType.Decimal, pValue: maxAuthLimit),
SqlHelperExtension.CreateInParam(pName: "@UserId", pType: SqlDbType.Int, pValue: userId),
SqlHelperExtension.CreateInParam(pName: "@IpAddress", pType: SqlDbType.VarChar, pValue: ipAddress, size: 20),
SqlHelperExtension.CreateInParam(pName: "@SavedBy", pType: SqlDbType.VarChar, pValue: savedBy, size: 30)
];
_ = tc.ExecuteNonQuerySp(spName: "dbo.SaveAuthorizeLimit", parameterValues: p);
tc.End();
returnValue = true;
}
catch (Exception ie)
{
tc?.HandleError();
throw DBCustomError.GenerateCustomError(ie);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
return returnValue;
}
public async Task<UserAuthorizeLimitResponse> GetAuthorizeLimitAsync(int userId)
{
UserAuthorizeLimitResponse response = new() { Value = 0 };
try
{
using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
try
{
using IDataReader dr = tc.ExecuteReader(commandText: "SELECT LoginId, MaxAuthLimit FROM dbo.Users WHERE UserId=%n", args: userId);
if (dr.Read())
{
response.LoginId = dr.GetString(0);
response.Value = dr.IsDBNull(1) ? 0 : dr.GetDecimal(1);
}
dr.Close();
tc.End();
response.ReturnStatus = 200;
}
catch (Exception ie)
{
tc?.HandleError();
throw DBCustomError.GenerateCustomError(ie);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
return response;
}
#region Private functions
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <param name="loginId"></param>
/// <param name="enfStgPwd"></param>
/// <param name="minLen"></param>
/// <param name="maxLen"></param>
/// <param name="reservedWords"></param>
/// <exception cref="Exception"></exception>
private void ReadPwdParams(int userId, string loginId, out bool enfStgPwd, out short minLen, out short maxLen, out string reservedWords)
{
try
{
enfStgPwd = false;
minLen = maxLen = 0;
reservedWords = string.Empty;
using TransactionContext tc = TransactionContext.Begin(_settings.DefaultConnection.ConnectionNode);
try
{
bool loginIdCantPwd = false;
using (IDataReader dr = tc.ExecuteReader("SELECT EnfStgPwd, PwdMinLen, PwdMaxLen, PwdRsvdWords, LoginIdCantPwd FROM ThisSystem"))
{
if (dr.Read())
{
enfStgPwd = Convert.ToBoolean(dr.GetInt16(0));
minLen = dr.GetInt16(1);
maxLen = dr.GetInt16(2);
reservedWords = dr.IsDBNull(3) ? string.Empty : dr.GetString(3);
loginIdCantPwd = !dr.IsDBNull(4) && dr.GetInt16(4) != 0;
}
dr.Close();
}
if (string.IsNullOrEmpty(loginId) && loginIdCantPwd && userId > 0)
{
using IDataReader dr = tc.ExecuteReader("SELECT LoginId FROM Users WHERE UserId=%n", userId);
if (dr.Read())
{
loginId = dr.IsDBNull(0) ? string.Empty : dr.GetString(0);
}
dr.Close();
}
tc.End();
if (loginIdCantPwd && !string.IsNullOrEmpty(loginId))
{
reservedWords = string.IsNullOrEmpty(reservedWords) ? loginId : $"{reservedWords},{loginId}";
}
}
catch (Exception ie)
{
tc?.HandleError();
throw DBCustomError.GenerateCustomError(ie);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
}
/// <summary>
///
/// </summary>
/// <param name="password"></param>
/// <param name="minLen"></param>
/// <param name="maxLen"></param>
/// <param name="enfStgPwd"></param>
/// <param name="reservedWords"></param>
/// <param name="daLastPwds"></param>
/// <param name="pwdHistories"></param>
/// <param name="actPwdHistories"></param>
/// <exception cref="Exception"></exception>
private void CheckPasswordHistory(string password, short minLen, short maxLen, bool enfStgPwd, string reservedWords, int daLastPwds, Queue<string> pwdHistories, List<string> actPwdHistories)
{
try
{
ValidatePwdPolicies(password: password, minLen: minLen, maxLen: maxLen, enfStgPwd: enfStgPwd, reservedWords: reservedWords);
password = EncryptPassword(password: password);
if (daLastPwds > 0 && actPwdHistories.Contains(password))
throw new InvalidOperationException($"You cannot use this password, because it was used in last {daLastPwds} passwords.");
if (pwdHistories.Count >= 5)
pwdHistories.Dequeue();
pwdHistories.Enqueue(password);
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
}
/// <summary>
/// Validates a password against specified policies, including length constraints, reserved words, and strong password requirements.
/// </summary>
/// <remarks>This method performs validation based on the provided policies and throws an exception if the password does not comply.
/// Ensure that all parameters are correctly configured before calling this method.</remarks>
/// <param name="password">The password to validate. Cannot be null or empty.</param>
/// <param name="minLen">The minimum allowed length for the password. Must be greater than 0.</param>
/// <param name="maxLen">The maximum allowed length for the password. Must be greater than 0.</param>
/// <param name="enfStgPwd">A value indicating whether strong password enforcement is enabled. If <see langword="true"/>, the password
/// must contain at least one uppercase letter, one lowercase letter, one number, and one special character (!, @, #, $, %, ^, &, *, ?).</param>
/// <param name="reservedWords">A comma-separated list of reserved words that cannot be included in the password. Cannot be null or empty.</param>
/// <exception cref="InvalidOperationException">Thrown if the password violates any of the specified policies, including: <list type="bullet">
/// <item><description>Contains a reserved word.</description></item> <item><description>Does not meet the minimum length requirement.</description></item> <item>
/// <description>Exceeds the maximum length requirement.</description></item> <item><description>Fails strong password enforcement when <paramref
/// name="enfStgPwd"/> is <see langword="true"/>.</description></item> </list></exception>
private static void ValidatePwdPolicies(string password, short minLen, short maxLen, bool enfStgPwd, string reservedWords)
{
try
{
if (!string.IsNullOrEmpty(password) && !string.IsNullOrEmpty(reservedWords))
{
List<string> words = [.. reservedWords.Split(',')];
foreach (string word in words)
{
if (password.Contains(word, StringComparison.InvariantCultureIgnoreCase))
throw new InvalidOperationException($"[{word}] can not be used in password.");
}
}
if (minLen > 0 && password.Length < minLen)
throw new InvalidOperationException($"Minimum length of Password is {minLen}");
if (maxLen > 0 && password.Length > maxLen)
throw new InvalidOperationException($"Maximum length of Password is {maxLen}");
if (enfStgPwd && !Global.StringFunctions.IsStrongPassword(password))
throw new InvalidOperationException("Must have Upper & Lower case character, a Number and a Special character (!, @, #, $, %, ^, &, *, ?).");
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
}
/// <summary>
///
/// </summary>
/// <param name="password"></param>
/// <returns></returns>
private string EncryptPassword(string password)
{
try
{
string pwdSecretKey = GlobalFunctions.ConvertFromBase64String(_settings.PwdSecretKey);
return Global.CipherFunctions.EncryptByAES(privateKey: pwdSecretKey, publicKey: pwdSecretKey, data: password);
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
}
/// <summary>
///
/// </summary>
/// <param name="tc"></param>
/// <param name="authValue"></param>
/// <param name="validMinutes"></param>
/// <param name="userId"></param>
private static void SetAuthValue(TransactionContext tc, string authValue, int validMinutes, int userId)
{
try
{
SqlParameter[] p =
[
SqlHelperExtension.CreateInParam(pName: "@AuthValue", pType: SqlDbType.VarChar, pValue: authValue, size: 10),
SqlHelperExtension.CreateInParam(pName: "@ValidMinutes", pType: SqlDbType.Int, pValue: validMinutes),
SqlHelperExtension.CreateInParam(pName: "@UserId", pType: SqlDbType.Int, pValue: userId)
];
_ = tc.ExecuteNonQuerySp(spName: "dbo.SetAuthValue", parameterValues: p);
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
}
/// <summary>
///
/// </summary>
/// <param name="tc"></param>
/// <param name="userId"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
private static int GetPendingNotifCount(TransactionContext tc, int userId)
{
try
{
SqlParameter[] p =
[
SqlHelperExtension.CreateInParam(pName: "@UserId", pType: SqlDbType.Int, pValue: userId),
SqlHelperExtension.CreateOutParam(pName: "@NotifCount", pType: SqlDbType.Int, pValue: 0)
];
_ = tc.ExecuteNonQuerySp(spName: "dbo.GetPendingAuthCountByUser", parameterValues: p);
return (p[1].Value != null && p[1].Value != DBNull.Value) ? Convert.ToInt32(p[1].Value) : 0;
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
}
/// <summary>
///
/// </summary>
/// <param name="parent"></param>
/// <param name="data"></param>
/// <param name="pmns"></param>
private static void MakeHierarchy(GroupPermission parent, List<GroupPermission> data, List<GroupPermission> pmns)
{
try
{
IEnumerable<GroupPermission> children = data.Where(x => x.ParentId == parent.ModuleId && x.Visible && pmns.Where(y => y.AllowSelect).Select(z => z.ModuleId).Contains(x.ModuleId));
parent.Children.AddRange(children);
foreach (GroupPermission child in parent.Children)
{
MakeHierarchy(parent: child, data: data, pmns: pmns);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
}
/// <summary>
///
/// </summary>
/// <param name="src"></param>
/// <param name="dst"></param>
private void CopyHierarchy(GroupPermission src, MenuItem dst)
{
try
{
if (src.Children?.Count > 0)
dst.Items = [];
foreach (GroupPermission srcChild in src.Children)
{
MenuItem dstChild = srcChild.Copy();
dstChild.Label = _menuSettings?.GetItem(dstChild.ModuleId, dstChild.Label).Value;
dst.Items.Add(dstChild);
CopyHierarchy(src: srcChild, dst: dstChild);
}
}
catch (Exception e)
{
throw new InvalidOperationException(e.Message, e);
}
}
public Task<bool> SaveAttributesAsync(int userId, int clientType, string ipAddress, int attributeSetBy, List<string> ukIds)
{
throw new NotImplementedException();
}
#endregion
}
internal class UserSearchResponse
{
}
}